TS与数组的那些事儿😏

引言

TS 是 JavaScript 的超集!那 TS 可以实现类似数组的方法吗?今天我们就来探索 TS 那些有趣的玩法!

pop、push、shift、unshift

下面我们会用到一些 TS 高级语法,有不懂的可以先去看 TS 文档传送门。让我们先从简单的着手~

pop

js 复制代码
    type Pop<T extends any[]> = T extends [...infer F, L] ? L : never
    
    // 让我们测试一下
    type p1 = Pop<[1,2,3,4,5]> // 5
    type p2 = Pop<['hello']> // hello

这儿用到了 extends(TS2.8版本) 语法、infer(TS2.8版本) 语法、...(TS3.0版本)语法,后面会大量用到,不懂得可以先去做了解。

push

js 复制代码
    type Push<T extends any[], V> = V extends any[] ? [...T, ...V] : [...T, V]
    
    type p2 = Push<[1,2,3,4,5], ['hello', 'world']> // [1,2,3,4,5,hello,world]
    type p2 = Push<[1,2,3,4,5], ['hello', ['world']]> // [1,2,3,4,5,hello,[world]]
    type p4 = Push<[1,2,3,4], 5> // [1,2,3,4,5]

是不是 so easy! :)下面我们提高难度

shift、unshift 方法类似,大家可以自行尝试

reverse、flat、filter、splice、join

reverse(反转

js 复制代码
    type Reverse<T extends any[], R extends any[] = []> = T extends [infer F, ...infer L] ? Reverse<L, [F, ...R]> : R
    
    type r1 = Reverse<[1,2,3,4,5> // [5,4,3,2,1]

我们采用递归思想(下面基本都会用到递归,同学们食好瓜子er),先取出第一个值,然后递归放入我们的结果数组中,注意最后[F, ...R],别放反了!

flat(拍平,一马平川

js 复制代码
    type Flat<T extends any[]> = T extends [infer F, ...infer S] ? [...(F extends any[] ? Flat<F> : [F]), ...Flat<S>] : T
    
    type f1 = Flat<[[[4]]], 5]> // [4, 5]

没办法,继续递归~

filter(过滤

做之前仔细想一下,这里面是要作比较,判断两个类型是否一致,一致就过滤出来。那我们怎么判断呢?

js 复制代码
    // 这段代码有点啰嗦,各位同学可以试着精简一下
    type Filter<
        T extends any[],
        V,
        R extends any[] = []
        > = T extends [infer F, ...infer S]
                ? F extends V
                    ? Filter<S, V, [...R, F]>
                : Filter<S, V, R>
            : R
    
    type f1 = Filter<[1, 'bef', 2, any, 'dev'], string> // ['bef', any, 'dev'] | ['bef', 'dev']

我们发现上面的代码,产生了两种结果,这是为什么?(别问我,我也木鸡啊:)

其实这是 TS 类型分发问题,原理很简单,举个栗子

type a = any extends string ? 1 : 2,你会发现结果是联合类型 1 | 2,仔细想下很简单,any可以是任何东西,可以是 number,可以是 string ,那 number 是 string 类型吗?显然不是,返回 2 ,那 string 是 string 类型吗?显然是,返回 1 ,一联合就是 1 | 2。 原理我们知道了,怎么规避呢?在了解了什么情况下会产生类型分发,就很好解决了。只要它不是裸类型 (当然,字面量 作比较,是不会分发的),就不会分发了,我们可以在 F extends V 包一层,[F] extends [V] 就OK了

splice(删除、追加、替换

js 复制代码
type Splice<
    T extends any[],
    S extends number, // 开始删除的索引
    C extends number = T['length'], // 删除的个数
    IN extends any[] = [], // 需要替换的值
    SA extends any[] = [], // 用于计算开始的位置
    EA extends any[] = [], // 用于计算删除的个数
    F extends any[] = [] // 前面需要保留的值
    > = T extends [infer L, ...infer R]
            ? SA['length'] extends S
                ? EA['length'] extends C
                    ? [...F, ...IN, L, ...R] // [...F, ...IN, ...T]
                : Splice<R, S, C, IN, SA, [...EA, never], F>
            : Splice<R, S, C, IN, [...SA, never], EA, [...F, L]>
        : [...F, ...IN]

type a1 = Splice<[boolean, 1, 'a', never, string], 1, 2, [3, 3]> // [boolean, 3, 3, never, string]
type a2 = Splice<[boolean, 'never', 1, 2, string], 0> // []
type a3 = Splice<[boolean, any, number, 2, 'a'], 1, 1> // [boolean, number, 2, 'a']
type a4 = Splice<[boolean, any, number, 2, 'a'], 4, 0, [99]> // [boolean, any, number, 2, 99, 'a']

注意看第二个栗子(a2),删除的个数,默认删除开始位置到数组最后一项。在最后的结果中,须将当前的 L 放进去(就因为这个点,当初迷惑了我一下午:)

join(拼接

js 复制代码
type Join<
    T extends any[],
    R extends string = ''
    > = T extends [infer F, ...infer S]
            ? S['length'] extends 0
                ? `${R}${F}`
            : Join<S, `${R}${F}`>
        : ''

type s = Join<['h', 'e', 'l', 'l', 'o']> // hello

总结

上面介绍了 TS 与数组的不解之缘,可谓有趣的很。还有很多有趣的玩法,这里就不一一列举了。除了数组,还有字符串。有时间可以跟大家一起探讨~

相关推荐
MiyueFE20 小时前
🚀🚀五个前端开发者都应该了解的TS技巧
前端·typescript
ttod_qzstudio1 天前
基于typescript严格模式以实现undo和redo功能为目标的命令模式代码参考
typescript·命令模式
张志鹏PHP全栈1 天前
TypeScript 第十天,TypeScript面向对象之Class(二)
前端·typescript
慧一居士1 天前
ESLint 完整功能介绍和完整使用示例演示
前端·javascript·typescript
enzeberg2 天前
TypeScript 工具类型(Utility Types)
typescript
難釋懷2 天前
TypeScript类
前端·typescript
杰哥焯逊2 天前
基于TS封装的高德地图JS APi2.0实用工具(包含插件类型,基础类型)...持续更新
前端·javascript·typescript
工业甲酰苯胺3 天前
TypeScript枚举类型应用:前后端状态码映射的最简方案
javascript·typescript·状态模式
土豆骑士4 天前
简单理解Typescript 装饰器
前端·typescript
ttod_qzstudio4 天前
彻底移除 HTML 元素:element.remove() 的本质与最佳实践
前端·javascript·typescript·html