typescript 类型体操 之 189-easy-awaited
前言
在学习typescript的过程当中,有一个github库对其类型的学习特别有帮助,是一个有点类似于leetcode的刷题项目,能够在里面刷各种关于typescript类型的题目,本片文章带大家做其中简单难度的第十道题 189-easy-awaited
下面这个是类型体操github仓库:
189-easy-awaited
我们首先还是先通过题目的README来看一下题目的要求
看完 README 看似这道题好像非常的简单,用我们之前介绍过的 infer 关键字就能够轻松解决,但是看到测试用例,又发现没那么简单
import type { Equal, Expect } from '@type-challenges/utils'
type X = Promise<string>
type Y = Promise<{ field: number }>
type Z = Promise<Promise<string | number>>
type cases = [
Expect<Equal<MyAwaited<X>, string>>,
Expect<Equal<MyAwaited<Y>, { field: number }>>,
Expect<Equal<MyAwaited<Z>, string | number>>,
]
// @ts-expect-error
type error = MyAwaited<number>
结合题目给的README和测试case,我们就能够得出,题目是需要我们实现一个函数,能够获取到 Promise 中的返回值的类型,但是这里要注意的是,测试中的 Promise 是能够嵌套多个的,并且当传入 number 的时候要给出报错。
利用js进行对比学习
通过 JS 我们能够有很多种方式来获取到一个Promise对象里面的值,then方法 或者 async/await 都是简单的获取返回值的方法,所以在这里就不做太多的介绍,直接快进到 TS 获取返回值类型。
实现 Awaited
先根据之前介绍的 infer 关键字获取到 Promise 的一个返回值:
type MyAwaited<T> = T extends Promise<infer R> ? R : never;
这时候会发现测试例子还剩下两处报错,然后我们再来一个个解决。
递归取参
首先看一个报错的测试例子:
type MyAwaited<T> = T extends Promise<infer R> ? R : never;
type Z = Promise<Promise<string | number>>;
type A = MyAwaited<Z>
// type A = Promise<string | number>
错误的原因很明显,我们只获取了第一层的 Promise 返回值,但是 Promise 可能会存在多层嵌套
那么这里就要涉及到 TS 泛型中的递归的概念,这和 JS 中的递归是完全一样的,我们可以利用条件链来实现一个泛型的递归。
我们再来看一下之前写的泛型:
type MyAwaited<T> = T extends Promise<infer R>
? R
: never;
换一种写法可能就会比较容易发现,我们能够在true分支当中,继续对拿到的 R 进行判断,从而实现递归。当拿到的 R 还是一个被 Promise 包裹的类型的话,我们就将它在此丢到 MyAwaited 中,不然的话就返回。
type MyAwaited<T> = T extends Promise<infer R>
? R extends Promise<any>
? MyAwaited<R>
: R
: never;
这样子我们就能够成功拿到嵌套的 Promise 中的类型。
入参约束
这时候测试中还存在另一个错误,就是参数约束的问题
简单的给入参加上约束,这道题的测试就成功全部通过了。
type MyAwaited<T extends Promise<unknown>> = T extends Promise<infer R>
? R extends Promise<unknown>
? MyAwaited<R>
: R
: never;
知识点
关于上述提到了部分的知识点:
- infer 关键字
- 条件链
infer 关键字我们在之前的文章当中有介绍过,条件链可以参考官方文档中的介绍
不了解条件类型的话也可以优先看一下之前介绍条件类型的文章:
总结
今天这道题的知识点可能是之前没有见到过的,关系到了条件链和 infer 关键字,这两个知识点是之后做类型体操的一个很重要的基础,很有必要去掌握明白再来进行刷题。
转载自:https://juejin.cn/post/7103545848570576904