条件付き型は infer キーワードを使用することで、複雑なデータ型から型を抽出することを可能にします。代表的な例は、配列から要素の型を抽出することです。
type ElementType<T> = T extends (infer U)[] ? U : T;
ここで infer U は、配列 T の要素の型を計算することを可能にします。もし T が配列であれば、その要素の型が返され、それ以外の場合は T 自体が返されます。
使用例:
例:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
一つの条件付き型内で複数の infer を使用することはできますか?TypeScript はこのケースをどのように解釈しますか?
間違った答え:
正しい答え:
type FirstArgument<T> = T extends (infer F, ...any[]) => any ? F : never; // しかし関数と一緒に使う方が正確です: type Args<T> = T extends (...args: infer A) => any ? A : never;
逸話
開発者は関数が返すオブジェクトの型を取得する方法を記述しましたが、その関数が Promise を返す可能性を考慮しませんでした。結果として、返り値の型は常に Promise<any> となり、入れ子の conditional extract/infer を使用しなかったため、コード全体のリファクタリングが必要になりました。
逸話
プロジェクトでネストされた配列を展開するための汎用型を導入しましたが、条件に最終的な else-branch を指定するのを忘れました。TypeScript は正しくエラーを出しませんでしたが、一部のケースでは結果が never となり、外部ライブラリのいくつかのユーティリティ型の動作が壊れてしまいました。
逸話
同僚は大きなインターフェースからプロパティの型を抽出するために combine-conditional/infer-型を試みましたが、いくつかのプロパティが自身が union 型であることを考慮しませんでした。結果として、出力として予期しない union 型の組み合わせが生成され、コンパイラはそれを通過し、ロジックが正しく機能しませんでした。