TS5.5のInferred Type Predicatesでちょこっと気にしておきたいなと思ったこと

昨日TSKaigiに参加してとても楽しかった。そのキーノートスピーカーがDanielで、5.5の新機能を教えてくれた。

ので、今日は↓この記事のInferred Type Predicatesを手を動かしながら読んだ。面白かった。まだ5.5はベータ。

devblogs.microsoft.com

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 な値だからね。なるほどなー。

じゃあ、たとえば xstring | 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さんの記事が分かりやすかった!