TL;DR
戻り値の型に parameterName is Type という型述語を書いた関数。TypeScript に、その関数が true を返したときに引数の型を絞り込ませる。
なぜ必要か
TypeScript は typeof や instanceof、in などで型を絞り込むが、それだけでは表せない判定もある。ユーザー定義型ガードを使うと、判定のロジックを関数にまとめ、その結果で型を絞り込める。
仕組み
型述語の parameterName は、その関数の引数の名前でなければならない。この関数を変数に対して呼ぶと、TypeScript は if の分岐の中でその変数を指定した型に絞り込む。else の分岐では、その型ではないことも分かるので、ユニオン型の残りのメンバーに絞り込む。
例
type Fish = { swim: () => void }
type Bird = { fly: () => void }
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
}
if (isFish(pet)) {
pet.swim() // Fish
} else {
pet.fly() // Bird
}zoo.filter(isFish) のように filter に渡すと、Fish[] 型の配列が得られる。
注意点
コンパイラは関数の中身が型述語と合っているかを確かめず、関数が返した真偽値をそのまま信じる。判定を間違えると、誤った型に絞り込まれる。