TypeScript类型体操--FlattenDepth、ReadonlyDeep
大家好,我是苏先生,一名热爱钻研、乐于分享的前端工程师,跟大家分享一句我很喜欢的话:人活着,其实就是一种心态,你若觉得快乐,幸福便无处不在
github与好文
前言
前边六篇文章我们一共实现了29个工具类型,按照本专栏的规划,还差70个...
本节我们继续学习两个新的工具类型
提示
对于语法层面的知识点本系列(类型体操开头的标题)不会展开说明哈,可以自行搜索学习其他大佬的优质文章或者等我后续更新补充
FlattenDepth
上一小节,我们实现了Flatten,它的完整代码如下,本次只是在它的基础上进行迭代即可
实现
首先,我们增加参数二,它是一个数值类型,代表着具体的拍平深度
type FlattenDepth<T extends any[],D extends number>
我们的Flatten是一拍到底的,我们要做的就是在每一次拍之前判断一下当前拍到了哪,如果已经到达指定层数了,就不再继续递归了。为此,需要增加一个变量来进行记录
type FlattenDepth<T extends any[],D extends number,U extends any[]=[]>
有了变量U之后,我们每递归一次,就朝里丢一个值,值是什么无所谓,总之它的length代表着递归深度
[...U,1]
结合上一小节中对Flatten的分析,我们知道真正执行递归的是第三行的前半段,即
...Flatten<F>
故有实现如下
type FlattenDepth<T extends any[],D extends number,U extends any[]=[]> =
T extends [] ? [] : T extends [infer F, ...infer R]
? F extends any[]
? [...FlattenDepth<F,D,[...U,1]>,...FlattenDepth<R,D,U>]
: [F, ...FlattenDepth<R,D,U>]
: [T]
现在,它的执行效果和Flatten是一样的,因为我们还没有为递归添加出口。判断出口的条件即是U中的成员个数等于了参数D
U['length'] extends D ? T : "按原来的走"
最后,我们还需要为D设置默认值,以使得其兼容Flatten,理想状态下,应该让D的值默认恰好等于最大深度,这一点可以通过写一个辅助类型来做,不过我们这里就以1来代替了
D extends number = 1
使用示例
ReadonlyDeep
在12个工具类型一文中,我们已经实现了Readonly
它的局限在于,只对第一层有效,如下,深层的a和b并没有被添加上readonly标识
实现
正如你想的那样,我们只需要对T[K]再次进行递归即可,既然是递归,则势必要有出口,出口即当前的T不是一个对象类型时
keyof T extends never ? T : "按原来的继续"
故,完整实现如下
type DeepReadonly<T> = keyof T extends never
? T
: { readonly [k in keyof T]: DeepReadonly<T[k]> }
使用示例
下期预告
TupleToUnion
- 功能
数组类型转联合类型
- 使用示例
type Arr = ['1', '2', '3']
type Test = TupleToUnion<Arr> // '1' | '2' | '3'
如果本文对您有用,希望能得到您的点赞和收藏
订阅专栏,每周更新1-2篇类型体操,每月1-3篇vue3源码解析,等你哟😎
转载自:https://juejin.cn/post/7257922419319357496