inferの基本的な使い方です。
infer でできること
infer の動作はRustやScalaのパターンマッチに似ています。
型変数を conditional type の extends の中で宣言できます。
宣言した型変数の値はTypeScriptが推論してくれます。
type R<T> = T extends (...args:any[])=> infer V ? V:never;
上記の場合、Tが関数のとき T extends (...args:any[])=> infer V
はtrueになります。
infer は戻り値の位置に書かれているのでVの値はTの戻り値の型になります。
infer を使って宣言した型変数はconditional typeのtrueの分岐の中で参照できます。
infer を記述する位置を変えることでキャプチャの対象を変更できます。
例えば以下のようにできます。
// 関数の引数の型
type Args<T> = T extends (...args:infer A) => any ? A:never;
// タプルや配列の最初の要素の型
type First<T extends any[]> = T extends [infer F, ...any[]] ? F:never
// タプルや配列の最後の要素の型
type Last<T extends any[]> = T extends [...any[], infer L] ? L:never;
// Promiseの返値の型
type PromiseValue<T> = T extends Promise<infer V> ? V:never;
infer が使える場所
conditional type の extends の後ろ、? より手前のところです。
type A<T> = T extends `ここで使える` ? true:false;
conditional type 以外では使えません。
// infer は conditional type の途中でしか使えないので下のような書き方は間違い
type Args<T extends (...args:infer P)=> any> = P