typescript 类型体操 之 459-medium-flatten

287 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

前言

在学习typescript的过程当中,有一个github库对其类型的学习特别有帮助,是一个有点类似于leetcode的刷题项目,能够在里面刷各种关于typescript类型的题目,在上一篇文章中,我们完成了中等的第十八题,今天来做中等的第十九题 459-medium-flatten

下面这个是类型体操github仓库:

type-challenges/type-challenges: Collection of TypeScript type challenges with online judge (github.com)

459-medium-flatten

image.png

import type { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Flatten<[]>, []>>,
  Expect<Equal<Flatten<[1, 2, 3, 4]>, [1, 2, 3, 4]>>,
  Expect<Equal<Flatten<[1, [2]]>, [1, 2]>>,
  Expect<Equal<Flatten<[1, 2, [3, 4], [[[5]]]]>, [1, 2, 3, 4, 5]>>,
  Expect<Equal<Flatten<[{ foo: 'bar'; 2: 10 }, 'foobar']>, [{ foo: 'bar'; 2: 10 }, 'foobar']>>,
]

从README和测试用例中能够得出,我们需要实现一个工具函数 Flatten 能够将数组进行扁平化操作。

利用 JS 进行模拟学习

在JS中可以利用扩展字符串来进行数组解构,并且用some来判断数组中是否存在数组,以此来进行数组的不断拍平。

function flatten(arr: any[]) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr);
    }
    return arr;
}

image.png

实现 Flatten

和之前的题目很相似的思路,我们需要一个拍平后的数组,那么就把入参数组的每一项拿来做检测,对于数组和非数组做出单独的处理,去除每一项这种操作可以通过 infer 和 递归 进行配合实现。

T extends [infer Start, ...infer Rest]

利用 infer 拿出数组的第一项,如果是数组的话,就将数组进行以此拍平并且拼接剩下的元素再次递归,如果不是数组的话就拿剩下的元素丢入泛型中递归,第一个元素就可以跳过,一直重复到每一项都不是数组为止。

type Flatten<T> = T extends [infer Start, ...infer Rest]
    ? Start extends any[]
        ? Flatten<[...Start, ...Rest]>
        : [Start, ...Flatten<[...Rest]>]
    : T;

这样我们的测试例子就能够全部通过了。

知识点

关于上述提到了部分的知识点:

  1. Rest 参数
  2. infer 关键字

今天这道题难点在于思路,解法和之前的大部分题目都是非常相似的。

总结

今天我们做完了中等的第十九题,题目属于比较常规的问题,主要在于能够想到递归判断数组中的每一项,以及判断之后如何灵活运用扩展运算符来进行数组拆解和组合。