likes
comments
collection
share

TypeScript类型体操--Reverse、Filter、Flatten

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

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

github与好文

前言

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

本节我们继续学习元组相关的类型编程

TypeScript类型体操--Reverse、Filter、Flatten

提示

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

Reverse

  • 功能

将数组类型中的元素进行翻转

  • 实现

首先,它接收一个泛型参数T

type Reverse<T>

对于该泛型参数,我们需要对其进行约束,使其必须是数组类型

T extends any[]

接着,我们要想办法拿到数组中的单个元素,根据前两篇文章的学习,我想聪明的你已经知道了,使用扩展运算符取余并重新构建一个数组可以做到

[infer F,...infer R]

此时,显而易见的是,只需要对R和F进行位置调换就可以使得元素F位置被调整

[...R,F]

那么以此类推,让剩余元素R递归下去就能求出结果,最终实现如下

type Reverse<T extends any[]> = T extends [infer F,...infer R] ? [Reverse<R>,F] : T
  • 使用示例

TypeScript类型体操--Reverse、Filter、Flatten

Filter

  • 功能

从数组类型中挑选指定的类型并返回一个由挑选类型组成的新数组

  • 实现

首先,它接收两个泛型参数T,U

type Filter<T,U>

对于参数T,需要进行约束,使其必须为数组类型,至于参数U则为any类型

type Filter<T extends any[],U>

同样的我们通过重新构造数组的方式,获取到数组中的每一个元素,并利用infer保持其类型不变

[infer F,...infer R]

现在我们来对比当前元素F与泛型U之间的关系,如果F是被过滤元素集合中的一员,则它们之间一定存在着协变关系,那么我们就可以通过extends来判断是否具有父子关系来做相应的处理了

F extends U ?'进行下一轮比较' : ?

相信经过前边十几个数组相关的练习,你应该也想到了,没错,就是递归。如下,如果找到了,就保留,没有就过滤掉,并使用R进行下一轮的筛选

F extends U ?[F,...Filter<R,U>] : Filter<R,U>

因此,我们的最终实现版本如下

type Filter<T extends any[],U> = T extends [infer F,...infer R] ? 
                                 F extends U ?
                                     [F,...Filter<R,U>]
                                     :Filter<R,U>
                                 :[]
  • 使用示例

TypeScript类型体操--Reverse、Filter、Flatten

Flatten

  • 功能

扁平化数组

  • 版本一

他接收一个泛型参数T,并且为数组类型

type Flatten<T extends any[]>

通过extends构造条件语句,使用infer推断类型

T extends [infer F, ...infer R]

对于此时得到的F和R,R确定为数组类型,F不确定,因此对F进行条件判断

F extends any[]

如果F是一个数组类型,则将F和R丢给Flatten继续递归

[...Flatten<F>,...Flatten<R>]

否则仅递归求R即可

[F, ...Flatten<R>]

至于T的非数组类型,我们将其包装成数组返回即可

[T]

故,完整实现如下

type Flatten<T extends any[]> = T extends [infer F, ...infer R]
    ? F extends any[] 
    ? [...Flatten<F>,...Flatten<R>]
    : [F, ...Flatten<R>]
    : [T]
  • 版本二

版本一的实现能将数组T的成员拍平,但是会产出冗余的代码,如下,多出来了N个空数组

TypeScript类型体操--Reverse、Filter、Flatten

这主要是因为在对最后一个成员进行处理时,R是一个空数组,当进行下一次递归时将R传递给Flatten后会取到[T],故我们需要对空数组进行单独处理,修改后的代码如下

type Flatten<T extends any[]> = T extends [] ? [] : T extends [infer F, ...infer R]
    ? F extends any[] 
    ? [...Flatten<F>,...Flatten<R>]
    : [F, ...Flatten<R>]
    : [T]
  • 使用示例

TypeScript类型体操--Reverse、Filter、Flatten

下期预告

FlattenDepth

  • 功能

允许对数组按指定的深度进行拍平

  • 使用示例
type a = FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2> // [1, 2, 3, 4, [5]]

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

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

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