type-challenges/README.md at main · TIMPICKLE/type-challenges · GitHub
infer的理解: 二元一次方程的 x,是一个未知的变量。
类比到TS, infer x 是指一个未知的类型。
If we have a type which is wrapped type like Promise. How we can get a type which is inside the wrapped type?
For example: if we have Promise<ExampleType>
how to get ExampleType?
type ExampleType = Promise<string> type Result = MyAwaited<ExampleType> // string
理解一下题目意思,你得解析出来promise的T的类型是什么,如果是联合类型,也需要解析出。
开始敲代码
测试用例:
import type { Equal, Expect } from '@type-challenges/utils'
type X = Promise<string>
type Y = Promise<{ field: number }>
type Z = Promise<Promise<string | number>>
type Z1 = Promise<Promise<Promise<string | boolean>>>
type T = { then: (onfulfilled: (arg: number) => any) => any }
type cases = [
Expect<Equal<MyAwaited<X>, string>>,
Expect<Equal<MyAwaited<Y>, { field: number }>>,
Expect<Equal<MyAwaited<Z>, string | number>>,
Expect<Equal<MyAwaited<Z1>, string | boolean>>,
Expect<Equal<MyAwaited<T>, number>>,
]
首先:
1. extens限制类型
type MyAwait<T> = T extends Promise<>;
2. 然后使用infer X 来设置一个未知的类型
type MyAwait<T> = T extends Promise<infer X>;
3. 然后返回结果, 三元表达式
type MyAwait<T> = T extends Promise<infer X> ? X : never;
4. 现在解决 测试用例的第三个,嵌套的promise,使用递归
type Z1 = Promise<Promise<Promise<string | boolean>>>
type MyAwait<T> = T extends Promise<infer X> ? MyAwait<X> : never;
5 检查一下递归出口
type MyAwait<T> = T extends Promise<infer X> ? MyAwait<X> : T;
6. 再处理一下非promise类型的参数
type MyAwait<T> = T extends Promise<infer X>
? X entends Promise<unknow>
? MyAwait<T>
: X
: never ;
woc看到github提交记录里有个b是这么写的,压缩大师:
type MyAwaited<T> = T extends PromiseLike<infer U> ? MyAwaited<U>: T
https://github.com/type-challenges/type-challenges/issues/21580
又涉及到的知识,关于TS的Like是什么东西:
javascript - Why does TypeScript use "Like" types? - Stack Overflow
interface PromiseLike<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1 = T, TResult2 = never>(
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): PromiseLike<TResult1 | TResult2>;
}