はじめに
こんにちは。フロントエンド開発課に所属している新卒1年目のm_you_sanと申します。
3月6日にTypeScript5.4がリリースされました。
そこで、今回は個人的に気になった機能についてピックアップして紹介したいと思います。
型の絞り込み
関数クロージャ内の型の絞り込みの挙動が少し変わりました。
以下のgetUrls
では、まず始めにtypeof演算子を使用して、第一引数のurl
がstring型かどうかを確認しています。
string型であった場合、URL
のインスタンスを生成します。
その後、map
関数内でURL
のプロパティであるsearchParams
を使用しています。
function getUrls(url: string | URL, names: string[]) { if (typeof url === "string") { url = new URL(url); } return names.map(name => { url.searchParams.set("name", name); return url.toString(); }); }
このとき従来の挙動の場合、map
関数のクロージャ内では、if (typeof url === "string")...
内で絞り込んだ型情報が保持されず、url
がstringとURLのユニオン型になるため、searchParams
の部分でエラーが発生します。
そのため、map
関数クロージャ内で再度、型情報を絞り込む必要がありました。
return names.map(name => { // もう一度型情報を絞り込む if (typeof url === "string") return; url.searchParams.set("name", name); return url.toString(); });
しかし、5.4からクロージャ内で型情報が保持されるようになったため、上記のようにわざわざもう一度型情報を絞り込む必要がなくなりました。
ただし、以下のようにネストされた関数内で、型情報を絞り込んだ変数が代入された場合は、型情報が保持されなくなります。
function printValueLater(value: string | undefined) { if (value === undefined) { value = "missing!"; } setTimeout(() => { value = value; }, 500); setTimeout(() => { // エラーが発生する console.log(value.toUpperCase()); }, 1000); }
また、functionを使って関数宣言をした場合、ホイスティングができるため、型情報を保持することができません。
以下のコードの場合、toUpperCaseFn
はif (value === undefined)...
より前に呼び出すことが可能なので、value
をstringに絞り込むことができません。
アロー関数の場合は、ホイスティングができないので、正常に型情報を絞り込むことが可能です。
function printValueLater(value: string | undefined) { // ここで呼び出すことが可能 // toUpperCaseFn(); if (value === undefined) { value = "missing!"; } function toUpperCaseFn() { // エラーが発生する console.log(value.toUpperCase()); } // エラーは発生しない const toUpperCaseFn2 = () => console.log(value.toUpperCase()); }
NoInfer
NoInferは新しく追加されたユーティリティ型で、不要な型推論をブロックすることができます。
以下のコードでは、colors
の配列要素の一部がdefaultColor
の型になるようにしています。
しかし、配列の要素にないものをdefaultColor
に設定しても、型推論が効いてしまうため、型エラーが発生しません。
この場合、defaultColor
からジェネリクスC
を推論させないようにする必要があります。
function createStreetLight<C extends string>(colors: C[], defaultColor?: C) { // ... } createStreetLight(["red", "yellow", "green"], "blue");
そこで、NoInferを使用すると型推論がブロックされ、defaultColor
がcolors
の配列要素の一部であることをチェックできるようになります。
function createStreetLight<C extends string>(colors: C[], defaultColor?: NoInfer<C>) { // ... } // blueは配列の要素に存在しないため、エラーが発生 createStreetLight(["red", "yellow", "green"], "blue");
まとめ
今回は、TypeScript5.4の新機能から個人的に気になったものを紹介しました。
クロージャ内の型情報の保持は、今後開発を進める中で役立つ場面が出てくるのではないかと思いました。
5.4の機能について、更に詳しく知りたい方は、リリースノートをご覧ください。
参考資料