infer
inferはConditional Typesの中で使われる型演算子です。inferは「推論する」という意味でextendsの右辺にのみ書くことができます。
ユーティリティ型ReturnType<T>の例からinferを知る
ある関数の戻り値の型を取得するユーティリティ型ReturnType<T>があります。ReturnType<T>は次のように定義されています。
tstypeReturnType <T extends (...args : any) => any> =T extends (...args : any) => inferR ?R : any;
tstypeReturnType <T extends (...args : any) => any> =T extends (...args : any) => inferR ?R : any;
試しに使ってみましょう。
tsconstrequest = (url : string):Promise <string> => {returnfetch (url ).then ((res ) =>res .text ());};typeX =ReturnType <typeofrequest >;
tsconstrequest = (url : string):Promise <string> => {returnfetch (url ).then ((res ) =>res .text ());};typeX =ReturnType <typeofrequest >;
typeofは変数から型を取得する演算子です。JavaScriptのtypeofとは異なるので注意してください。
📄️ typeof型演算子
TypeScriptのtypeofは変数から型を抽出する型演算子です。次は、変数pointにtypeof型演算子を用いて、Point型を定義する例です。このPoint型は次のような型になります。
このように関数requestの型から戻り値の型を取得することができました。
ReturnType<T>の解説
ReturnType<T>の構造を知るためにはまずT extends (...args: any) => anyが何かを知る必要があります。これは一般的な関数の型を示しています。任意の個数で任意の型の引数を受け取り、任意の型の値を返すことを示しています。Tは任意の関数を示しています。
そして戻り値の部分が=> infer R ? R : anyとなっており、Tが関数である場合は戻り値の型であるR、そうでない場合はanyを返すという意味になっています。
総合的にReturnType<T>はTが関数に割り当て可能である場合はR、そうでない場合はanyを返します。
inferを使うことによってある型Tが配列である場合はその要素の型、そうでない場合はneverを返すFlatten<T>を作ってみましょう。
tstypeFlatten <T > =T extends (inferU )[] ?U : never;
tstypeFlatten <T > =T extends (inferU )[] ?U : never;
このFlatten<T>を使ってみましょう。
tstypeA =Flatten <string>;typeB =Flatten <string[]>;typeC =Flatten <string[][]>;typeD =Flatten <[string, number]>;
tstypeA =Flatten <string>;typeB =Flatten <string[]>;typeC =Flatten <string[][]>;typeD =Flatten <[string, number]>;
2次元配列にFlatten<T>を適用すると1次元配列が返ってくることが、タプル型にFlatten<T>を適用するとユニオン型が返ってくることがわかります。