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[] 型の配列が得られる。

注意点

コンパイラは関数の中身が型述語と合っているかを確かめず、関数が返した真偽値をそのまま信じる。判定を間違えると、誤った型に絞り込まれる。

関連

出典