哈喽!最近要赶uni-app迭代项目的需求,一直没空更,今天周末终于有空了。上回梳理了一下掌握TS类型体操的必备知识,这里再强调一下体操最常用到的extends和infer关键字,是必须掌握的。那么现在我们来做个热身操哈~
先上第一个需求~
这个需求很简单,实现类型 Awaited,比如从 Promise<ToDoType> 拿到 ToDoType
这里提一下,不要一看到Promise对象就习惯性想到要用ES8 的 async 函数,执行 await 拿到Promise对象,因为TS永远不会去执行代码
需求仅仅是要从 Promise< T > 提取出泛型 T
基于业务经验,我们一般会想到用 infer 来解决
type MyAwaited<T> = T extends Promise<infer U> ? U : never
但仅仅是这样的话,我们就没有考虑到Promise一些嵌套回调的场景,类似下面这样的
Promise.resolve().then(res=>{
console.log('1')
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('2')
resolve('newPromise')
},1000)
}).then(res=>{
console.log('3')
return 'newPromise1'
})
}).then(res=>{
console.log('4',res)
})
考虑到这里,就很自然地会和递归联系到了一起,所以完成这个需求的标准答案是
// 标准答案考虑了嵌套 Promise 的场景,采用用递归的写法
type MyAwaited<T extends Promise<unknown>> = T extends Promise<infer P>
? P extends Promise<unknown> ? MyAwaited<P> : P
: never
这里附上原题链接: github.com/type-challe…
是不是有点不够,再看下第二个需求~
实现类型 FirstItem、LastItem , FirstItem< T >作用是获取元组第一项的类型,LastItem< T >作用是获取元组最后一项的类型
//demo
type arr1=[1,2,3]
type arr2=['南山','橘子','一泽']
//ToDo
type res1 = FirstItem<arr1> // 1
type res2 = FirstItem<arr2> // '南山'
type res3 = LastItem<arr1> // 3
type res4 = LastItem<arr2> // '一泽'
我们都知道ES6的数组解构/展开 ,TS里也可以用的,所以结合infer,答案是
// 实现FirstItem
type FirstItem<T extends unknown[]> = T extends [infer P, ...infer _ ] ? P : never;
// 实现LastItem
type LastItem<T extends unknown[]> = T extends [...infer _ , infer P] ? P : never;
特别说明下
- 这里只需要一个泛型,不需要再使用另一个新泛型表示其他元素的类型,所以用
_ - 不能用
...Rest代替...infer P/_因为TS里不能随便使用一个未定义的泛型