TypeScript 5.5からは関数からType predicatesの型推論が有効になるよ!
去る2024年4月25日にTypeScript 5.5 ベータ版リリースの情報が発表されました。
どうやら今回の目玉機能は、『推論されたtype predicate』ということです。
この記事では、これまでとこれからでtype predicate
がどのように変わるのかをお話ししたいと思います。
環境の用意
これまでの動作を確認するための環境は、既に用意していた別プロジェクトのランタイムを利用しました。バージョンは5.1.6
です。
ベータ版環境は新たに用意します。公式のリリースノートにもありますが、以下のコマンドを実行するだけです。
npm install -D typescript@beta
これでベータ版の実行環境ができたのですが、VSCodeさんが最新版の仕様で型推論を行なってくれません。
ので、調教強制的にいうことを聞かせます。
やり方は、適当なtsファイル開いてshift
+ cmd
+ p
→ typescript:Select Typescript Version
から正しいバージョンを選択します。
上記のように、選択肢が表示されるため、5.5.0-beta
を選択すれば準備OKです。
そもそも、Type predicateって?
これは名前に馴染みがない方でも、普段コードを書く中でナチュラルに使っている方も多いハズ。
例えば以下のコード。
function isCar(car: Car | undefined): car is Car {
return car !== undefined;
}
このような型ガードを書くことでundefined
を間引き、安全にCar
として扱うことができます。
このcar is Car
の部分がType predicate
と呼ばれるものです。
改めて、5.5以前のコードを確認する
Type predicate
が何かわかったところで、以下のコードを見てください。
interface Car {
maker: string;
carNumber: number;
run(): void;
}
declare const makerCars: Map<string, Car>;
function isCar(car: Car | undefined){
return car !== undefined;
}
function runCar(makers: string[]) {
const cars = makers
.map(maker => makerCars.get(maker))
.filter(car => isCar(car));
// なぜか型がCar | undefinedになってしまう
for (const car of cars) {
car.run();
}
}
先ほどの話を踏まえるのであれば、isCar
の戻り値は明記していないものの型推論が働き、.filter
によってCar
型のオブジェクトのみに絞られるハズです。
その後car.run()
は問題なく実行できそうですが…
car
はundefined
と推定されてしまっています。なぜこのようなことが起こるのでしょうか?
5.5以前はType predicateを型推論してくれない
では、TypeScriptは何を推論しているのか確認してみると…
どうやら愚直にboolean
と推論してしまっているようです。間違ってはいませんが、文脈からは少し外れてしまているようにも思えますね。
5.5からはType predicateを型推論してくれる
では、先ほどと同じコードを5.5
の実行環境で確認してみると…
エラーが消えました!そしてisCar
の型推論はというと…
素晴らしい👏 car is Car
が推論されていますね👏
おわりに
詳細はこの機能の実装者であるDan Vanderkamさんのブログに記載されています。
対応にあたってのもろもろの経緯が書かれていて、とても面白いです。
Discussion