TL;DR
条件分岐などの実行時のチェックをもとに、ある位置での値の型を、宣言された型より具体的な型に絞ること。TypeScript では narrowing と呼ぶ。
なぜ必要か
number | string のようなユニオン型の値は、そのままでは number にしかないメソッドを呼べない。TypeScript のハンドブックによると、typeof padding === "number" のようなチェックを書くと、TypeScript はその分岐の中で値を number として扱う。型の絞り込みがあるので、JavaScript でふだん書くチェックをそのまま型の安全性につなげられる。
仕組み
TypeScript は、プログラムが通りうる実行経路をたどり、各位置で値が取りうる最も具体的な型を求める。到達可能性に基づくこの解析を制御フロー解析と呼ぶ。TypeScript は、型ガードと呼ばれる特別なチェックや代入に出会うたびに型を絞り込む。
ハンドブックでは、次のような絞り込みの方法を挙げている。
typeof、instanceof、in演算子による型ガード- 真偽値としての評価や、
===や!= nullなどの等価性のチェック pet is Fishの形の型述語を返すユーザ定義の型ガードkindのような共通のリテラル型のプロパティによる、判別共用体の絞り込み- すべてのケースを処理した後に残る
never型を使った網羅性チェック
例
function padLeft(padding: number | string, input: string): string {
if (typeof padding === "number") {
return " ".repeat(padding) + input // padding: number
}
return padding + input // padding: string
}注意点
typeof null は "object" になるので、typeof x === "object" だけでは null を除けない。Effective TypeScript 第2版 ―型システムの力を最大限に引き出す83項目 によると、値のエイリアス(別の変数に入れたもの)は型の絞り込みを妨げることがあるので、エイリアスを作ったら一貫してそれを使う。また、ユーザ定義型ガードは、本体が型述語と正しく対応しているかを誰もチェックしないので、型アサーションと同じく安全ではない。