お題
Promise
の解決値の型Tを取得するユーティリティ型、Awaited
を自作する。
やりたいこと
type ExampleType1 = Promise<string>;
type ExampleType2 = Promise<Promise<string | boolean>>;
type ExampleType3 = { then: (onfulfilled: (arg: number) => any) => any };
type Result1 = MyAwaited<ExampleType1>; // => string
type Result2 = MyAwaited<ExampleType2>; // => string | boolean
type Result3 = MyAwaited<ExampleType3>; // => number
解答
type MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U>
? U extends PromiseLike<any>
? MyAwaited<U>
: U
: never;
解説
処理の流れ
-
T extends PromiseLike<any>
T
をPromiseLike
な型に制約する。 -
T extends PromiseLike<infer U> ...
infer U
でPromise
orPromiseLike
の中の型を抽出する。 -
U extends PromiseLike<any> ? MyAwaited<U> : U
抽出された型U
がPromiseLikeかどうかで条件分岐
= 入れ子になっているかどうかの確認。- 入れ子になっている場合
MyAwaited<U>
で再帰的に処理。 - 入れ子ではない場合
そのまま抽出されたU
を返す。
- 入れ子になっている場合
-
... : never
それ以外の場合にnever
を返す。
PrmosieLikeな型とは...
- thenメソッドを持つオブジェクトのことで、完全なPromiseである必要はない。
type ExampleType3 = { then: (onfulfilled: (arg: number) => any) => any };
- thenableオブジェクトとも呼ばれる。
inferとは...
参考記事
Promise<T>
Awaited<T>
今回の問題