type-challenges:FlattenDepth

20 阅读2分钟

FlattenDepth

问题描述

递归地将数组平铺x 次,x 为泛型传入的第二个参数,不传默认为1。

举例:

type a = FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2> // [1, 2, 3, 4, [5]]. flattern 2 times
type b = FlattenDepth<[1, 2, [3, 4], [[[5]]]]> // [1, 2, 3, 4, [[5]]]. Depth defaults to be 1

如果提供了深度,那么它肯定是正整数。

// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'type cases = [
  Expect<Equal<FlattenDepth<[]>, []>>,
  Expect<Equal<FlattenDepth<[1, 2, 3, 4]>, [1, 2, 3, 4]>>,
  Expect<Equal<FlattenDepth<[1, [2]]>, [1, 2]>>,
  Expect<Equal<FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2>, [1, 2, 3, 4, [5]]>>,
  Expect<Equal<FlattenDepth<[1, 2, [3, 4], [[[5]]]]>, [1, 2, 3, 4, [[5]]]>>,
  Expect<Equal<FlattenDepth<[1, [2, [3, [4, [5]]]]], 3>, [1, 2, 3, 4, [5]]>>,
  Expect<Equal<FlattenDepth<[1, [2, [3, [4, [5]]]]], 19260817>, [1, 2, 3, 4, 5]>>
]
​
// ============= Your Code Here =============
// 答案1
type FlattenOnce<T extends any[]> = T extends [infer F, ...infer R]
  ? [...(F extends [...infer K] ? K : [F]), ...FlattenOnce<R>]
  : T
type FlattenDepth<T, Times extends number = 1, P extends any[] = []> = T extends any[]
  ? P extends { length: Times }
    ? T
    : T extends FlattenOnce<T>
    ? T
    : FlattenDepth<FlattenOnce<T>, Times, [...P, any]>
  : never
// 答案2
type FlattenDepth<T extends any[], S extends number = 1, U extends any[] = []> = U['length'] extends S
  ? T
  : T extends [infer F, ...infer R]
  ? F extends any[]
    ? [...FlattenDepth<F, S, [...U, 1]>, ...FlattenDepth<R, S, U>]
    : [F, ...FlattenDepth<R, S, U>]
  : T
​

又上难度了,判断是不是整数需要用到数组的长度,这个思路得记住。

参考文章 这里,搬过来了。

题目要求写一个深度打平,并规定打平层数的类型。我们可以逐步简化问题,再慢慢添加条件来实现。我们先不考虑打平层数,只考虑深度打平。同样,写深度打平之前,我们先看看打平一层怎样实现:

type FlattenOnce<T extends any[]> = T extends [infer F, ...infer R]
  ? F extends any[]
    ? [...F, ...FlattenOnce<R>]
    : [F, ...FlattenOnce<R>]
  : T

那么深度打平,其实就是将打平的操作,进行递归。那么上面代码那里进行打平了呢?那就是 ...F,因此我们只要递归这里就可以了:

type FlattenDepth<T extends any[]> = T extends [infer F, ...infer R]
  ? F extends any[]
    ? [...FlattenDepth<F>, ...FlattenDepth<R>]
    : [F, ...FlattenDepth<R>]
  : T

现在考虑下层数问题,ts 中需要比较具体的数字类型,通常都需要数组的 length 属性。那么我们可以增加一个数组类型参数 U,每次打平向它里面添加一个元素来达到 ”+1“ 的目的。然后每次递归时,判断层数和它的 length 是否一致,如果一致,说明打平层数够了,直接返回本身即可;否则继续递归。

type FlattenDepth<
  T extends any[],
  S extends number = 1,
  U extends any[] = []
> = U['length'] extends S
  ? T
  : T extends [infer F, ...infer R]
  ? F extends any[]
    ? [...FlattenDepth<F, S, [...U, 1]>, ...FlattenDepth<R, S, U>]
    : [F, ...FlattenDepth<R, S, U>]
  : T

需要注意,只有 ...F 的部分向 U 中添加了元素,进行了 ”+1“,因为只有这部分是真正进行打平操作的,而剩余参数 R 部分的递归,并没有进行打平,只是继续向后传递参数,因此这部分不 ”+1“。