はじめに
この投稿は、TypeScript学習者が書いています。条件型の中で使うinferについて、自身の理解のために整理します。inferは、型の形に合った部分の型をUやRなどの仮の名前で受け取り、取り出すための構文です。
1. inferはextendsの右辺に書く
inferは条件型のextendsの右辺にだけ書けます。合った位置の型をUなどの仮の名前で受け取り、条件が成り立つときはその型を結果として使います。
type Flatten<T> = T extends (infer U)[] ? U : never;
type A = Flatten<string[]>;
// string
type B = Flatten<string>;
// never
type C = Flatten<[string, number]>;
// string | number
Tが配列の形なら要素の型をUとして取り出し、そうでなければneverです。タプル型では要素のユニオン型になります。
2. Promiseの中身を取る
同じ考え方で、Promiseの型引数を取り出せます。
type Inner<T> = T extends Promise<infer R> ? R : T;
type A = Inner<Promise<string>>;
// string
type B = Inner<number>;
// number
Promiseなら中の型、そうでなければTそのものです。
3. 関数の戻り値を取る
ReturnTypeは、関数の戻り値の型を取り出すTypeScript組み込みの型です。
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
Tが関数型なら、戻り値の型をRとして取り出します。infer Rは、関数型の戻り値の位置に書きます。
type R = ReturnType<() => number>;
// number
type P = ReturnType<(x: string) => Promise<boolean>>;
// Promise<boolean>
ReturnTypeに渡すのは関数そのものではなく、関数の型です。typeof fnで関数から型を取る使い方もあります。
まとめ
-
inferは条件型のextends右辺で使い、合った位置の型をUやRなどの仮の名前で受け取ります。 - 配列の要素、
Promiseの型引数、関数の戻り値など、「型の一部」を取り出すのに使います。