TS easy-awaited 学习类型体操( type-challenges ) 的第四天

148 阅读1分钟

题目的地址

github.com/type-challe…

type MyAwaited<T> = any

type X = Promise<string>
type Y = Promise<{ field: number }>
type Z = Promise<Promise<string | number>>
type Z1 = Promise<Promise<Promise<string | boolean>>>

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>>,
]

// @ts-expect-error
type error = MyAwaited<number>

题目解析

第一步 : 限制传进来的值只能是 promise

 type MyAwaited<T extends Promise<any>> = any
// 防止 @ts-expect-error 报错
// type error = MyAwaited<number>

第二步: 如果只是为了解除数组的第一个元素报错 赋值 string 即可

 type MyAwaited<T extends Promise<any>> = string

第三步: 解决数组中第二个元素报错

使用 infer 设置一个变量 或者说是 一个未知数

type MyAwaited<T extends Promise<any>> = T extends Promise<infer X> ? X : X 
// 不管 X 是什么 我们只管返回 X(参数) 也就是 string 或者 { field: number }

第四步: 解决数组元素中的第三个和第四个报错

现在数组第三第四元素中的 promise 有了嵌套结构 Promise<Promise<string | number>>

我们可以使用递归, 只要是 promise 就递归

按照上面的写法 此时的 X 应该为 Promise<string | number T >

也有可能为数组中 前两 元素中的普通类型 也就是 string 或者 { field: number }

// 所以我们应该在进行限制  总共有两种可能
// 1. 为Promise<string | number> 此步骤应该让他递归并且将 X传入进去
// 2. string 等等非promise的参数
X extends Promise<any> ? MyAwaited<X> : X

最终的代码

type MyAwaited<T extends Promise<any>> = T extends Promise<infer X> 
? X extends Promise<any> ? MyAwaited<X> : X
: X  // 这个X可写可不写, 因为上面已经片段完毕,不会进入到此步骤