infer
inferはConditional Typesの中で使われる型演算子です。infer
は「推論する」という意味でextends
の右辺にのみ書くことができます。
ユーティリティ型ReturnType<T>
の例からinfer
を知る
ある関数の戻り値の型を取得するユーティリティ型ReturnType<T>
があります。ReturnType<T>
は次のように定義されています。
ts
typeReturnType <T extends (...args : any) => any> =T extends (...args : any) => inferR ?R : any;
ts
typeReturnType <T extends (...args : any) => any> =T extends (...args : any) => inferR ?R : any;
試しに使ってみましょう。
ts
constrequest = (url : string):Promise <string> => {returnfetch (url ).then ((res ) =>res .text ());};typeX =ReturnType <typeofrequest >;
ts
constrequest = (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>
を作ってみましょう。
ts
typeFlatten <T > =T extends (inferU )[] ?U : never;
ts
typeFlatten <T > =T extends (inferU )[] ?U : never;
このFlatten<T>
を使ってみましょう。
ts
typeA =Flatten <string>;typeB =Flatten <string[]>;typeC =Flatten <string[][]>;typeD =Flatten <[string, number]>;
ts
typeA =Flatten <string>;typeB =Flatten <string[]>;typeC =Flatten <string[][]>;typeD =Flatten <[string, number]>;
2次元配列にFlatten<T>
を適用すると1次元配列が返ってくることが、タプル型にFlatten<T>
を適用するとユニオン型が返ってくることがわかります。