likes
comments
collection
share

TypeScript类型体操--FlattenDepth、ReadonlyDeep

作者站长头像
站长
· 阅读数 45

大家好,我是苏先生,一名热爱钻研、乐于分享的前端工程师,跟大家分享一句我很喜欢的话:人活着,其实就是一种心态,你若觉得快乐,幸福便无处不在

github与好文

前言

前边六篇文章我们一共实现了29个工具类型,按照本专栏的规划,还差70个...

本节我们继续学习两个新的工具类型

TypeScript类型体操--FlattenDepth、ReadonlyDeep

提示

对于语法层面的知识点本系列(类型体操开头的标题)不会展开说明哈,可以自行搜索学习其他大佬的优质文章或者等我后续更新补充

FlattenDepth

上一小节,我们实现了Flatten,它的完整代码如下,本次只是在它的基础上进行迭代即可

TypeScript类型体操--FlattenDepth、ReadonlyDeep

实现

首先,我们增加参数二,它是一个数值类型,代表着具体的拍平深度

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

使用示例

TypeScript类型体操--FlattenDepth、ReadonlyDeep

ReadonlyDeep

在12个工具类型一文中,我们已经实现了Readonly

TypeScript类型体操--FlattenDepth、ReadonlyDeep

它的局限在于,只对第一层有效,如下,深层的a和b并没有被添加上readonly标识

TypeScript类型体操--FlattenDepth、ReadonlyDeep

实现

正如你想的那样,我们只需要对T[K]再次进行递归即可,既然是递归,则势必要有出口,出口即当前的T不是一个对象类型时

keyof T extends never ? T : "按原来的继续"

故,完整实现如下

type DeepReadonly<T> = keyof T extends never
  ? T
  : { readonly [k in keyof T]: DeepReadonly<T[k]> }

使用示例

TypeScript类型体操--FlattenDepth、ReadonlyDeep

下期预告

TupleToUnion

  • 功能

数组类型转联合类型

  • 使用示例
type Arr = ['1', '2', '3']

type Test = TupleToUnion<Arr> // '1' | '2' | '3'

如果本文对您有用,希望能得到您的点赞和收藏

订阅专栏,每周更新1-2篇类型体操,每月1-3篇vue3源码解析,等你哟😎

转载自:https://juejin.cn/post/7257922419319357496
评论
请登录