昨日TSKaigiに参加してとても楽しかった。そのキーノートスピーカーがDanielで、5.5の新機能を教えてくれた。
ので、今日は↓この記事のInferred Type Predicatesを手を動かしながら読んだ。面白かった。まだ5.5はベータ。
Inferred Type Predicatesってどういうもの?
こういう関数を書くと
function isString(x: string | number) { return typeof x === "string"; }
5.4までは、戻り値の型は単純に boolean
に推論される。
これが5.5からは、Type Predicateに推論される。
何が便利なの?
何が便利かって、これで型のNarrowingが便利に使えるようになる。 filter
が分かりやすいよね。
const strs = ["a", undefined, "b"].filter((x) => typeof x === "string");
これは、コードを読めば文字列だけの配列になっていることが分かるけど、5.4までのTypeScriptは (string | undefined)[]
として扱ってしまう。
5.5からはType Predicateに推論されるので string[]
として扱える。便利。
一応書いておくと5.4まででもType Predicateを明示的に使えば string[]
になる(ただ、Type Predicateを間違って書いちゃってもTSは信じてしまうので危なさがある)。
ちょこっと気にしておきたいなと思ったこと
こんな便利そうなInferred Type Predicatesについて、使うときにちょこっと気にしておきたいなと思ったことがある。
参照記事に書かれているのだけど、僕は記事をちゃんと読む前に、文字列 x
に対して !!x
をして「あれー?Type Predicateにならないなぁ」ってなってたので、さっそくはまっておいた(えっへん)。
↓これは5.5でもType Predicateに推論されない。
function isString(x: string | undefined) { return !!x; }
!!x
だと string
の一部が falsy の方に含まれるから。っぽい。""
は falsy な値だからね。なるほどなー。
じゃあ、たとえば x
が string | undefined
じゃなくて "abcde" | undefined
なら !!x
でもType Predicateになるってことなのかな?
なった。なるほどなー。同様に number
に対して !!x
もTypePredicateにはならない。0
が falsy だから。
これ、頭に入れておくと、実際に使い始めたときにハマらなくて良さそう。
他にも
- return が複数あったらだめ
- パラメータを変更(mutate)してたらだめ
って条件もあるから気をつけとこっと。
あと↓こういうのもだめね( (x) => x
)
この機能によってエラーになってしまうケース
これも記事に書いてある。さっきの配列の例だと (string | undefined)[]
じゃなくて string[]
になるから
5.4だと (string | undefined)[]
だったから undefined
が push できるけど
5.5だと string[]
だから怒られる
まぁ、こういうコードはないほうがいいから怒ってくれる方がいいね。
もういっこ
The function returns a boolean expression that’s tied to a refinement on the parameter.
って条件も書いてあるんだけど、これどういう意味か分かってない。誰か教えてください!
夕方に追記:あー。いま読み直してみて分かった。
「戻り値の型がType Predicateに推論されるのは、パラメータの型を狭めることに関係するbooleanを返す関数だよ」ってことか。勝手にすっきりした!
参照
夕方に追記。
Inferred Type Predicatesのことを検索してみたら、↓鹿野さんとKanonさんの記事が分かりやすかった!