美文网首页
TypeScript类型体操--数组攻略(中)

TypeScript类型体操--数组攻略(中)

作者: 习惯水文的前端苏 | 来源:发表于2023-06-13 14:29 被阅读0次

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

    前言

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

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

    image.png

    提示

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

    isTuple

    • 功能

    判断一个类型是否是元组

    • 实现

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

    type IsTuple<T>
    

    我们不应该限制T的类型,如果T是一个非元组,则直接返回false就好了

    type IsTuple<T> = T extends any[] ? true : false
    

    目前,对于readonly修饰符,我们的IsTuple会返回false

    image.png

    要解决这个问题,我们只需要将条件类型相应的增加readonly修饰符就可以了,这是因为带有修饰符的元组表示的范围更小,你可以认为它是没有修饰符的父类型

    image.png

    最后,我们思考数组和元组的区别,看下图,一个数组类型的length的返回类型为number

    image.png

    但是对于元组,length取到的却是一个具体的数字

    image.png

    为此,我们需要对length进行单独的处理

    type IsTuple<T> = T extends readonly any[] ? 
                        number extends T['length'] 
                        ?
                        false
                        : true
                        : false
    
    • 使用示例
    image.png

    lastIndexOf

    • 功能

    找到元素在元组中的位置,找不到返回-1

    • 实现

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

    type LastIndexOf<T,U>
    

    接着,我们对泛型参数进行约束:对于泛型T,应该是一个数组类型,而泛型U则是any类型

    type LastIndexOf<T exyends any[],U>
    

    然后,我们要想办法拿到最后一个元素,在上一节中我们介绍过,通过扩展运算可以达到该目的,如下,L即是最后一个元素,此时我们只需要借助infer关键字就可以拿到元素对应的类型了

    [...infer F,infer L]
    

    既然我们已经拿到了最后一个元素,那就可以与U进行比较判断了,我们知道,当两个类型一样或具有父子关系时,通过extends可以得到true,伪代码如下

    L extends U ? '得到其对应的位置' : '递归'
    

    我们分别来思考extends分两个分支:

    1-成立时,取位置

    上一节我们在分析Last工具类型时介绍过,T["length"]能够取到当前数组的长度,且它与元素对应的位置的T["length"]的取值减去1,这恰好是F的长度

    2-不成立时,进行递归

    这个比较简单,我们只需要将数组的最后一位删掉重新调用LastIndexOf就行了,好巧不巧的是,它又刚好是F

    综上所述,最终实现如下

    type LastIndexOf<T extends any[],U> = T extends [...infer F,infer L] ? 
                                            L extends U 
                                                ?
                                                F['length']
                                                : LastIndexOf<F,U>
                                            : -1
    
    • 使用示例
    image.png

    includes

    • 功能

    判断元素是否在元组中

    • 实现

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

    type Includes<T,U>
    

    泛型T的参数需要约束为数组类型

    type Includes<T extends any[],U> 
    

    接着我们要想办法拿到数组中的每一个元素与U进行比较,正如前文分析的那样,这肯定要用到类型递归

    T extends [...infer F,infer L] ? '判断是否存在' : '递归'
    

    事实上,按照上文LastIndexOf的实现思路这会变得很容易,不过由于多个条件类型会让代码变得难以阅读。所以,我们选择提取出一个公共类型来专门负责两个元素的比较

    type IsEqual<V,Item> = V extends Item ? true : false
    

    最后按照LastIndexOf的套路,我们比较完一个,就把已经比较过的元素丢弃掉,并重新调用includes,最终实现如下

    type Includes<Value extends any[], Item> =
        IsEqual<Value[0], Item> extends true
            ? true
            : Value extends [Value[0], ...infer rest]
                ? Includes<rest, Item>
                : false;
    
    • 使用示例
    image.png

    下期预告

    最后一个就当作是一个随堂练习啦,我们放在下一节中进行实现(ps:欢迎在评论区晒出你的实现思路🤩)

    Fill

    • 功能

    类型版本的数组填充

    • 示例
    type Result = Fill<[1, 2, 3], 'a'> // ['a', 'a', 'a']
    type Result2 = Fill<[1, 2, 3], 'a',1> // [1, 2, 'a']
    type Result3 = Fill<[1, 2, 3], 'a',1,2> // [1, 'a', 3]
    
    • 提示

    类型递归


    如果本文对您有用,希望能得到您的❤


    相关文章

      网友评论

          本文标题:TypeScript类型体操--数组攻略(中)

          本文链接:https://www.haomeiwen.com/subject/smpcydtx.html