Skip to content

31. Flatten #40

@astak16

Description

@astak16

题目

题目链接:Flatten解答

实现 Flatten,将多维元组打平

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"]
    >
  >
];

答案

方法一

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

// 另一种写法
type Flatten<T extends unknown[]> = T extends [infer F, ...infer Rest]
  ? F extends unknown[]
    ? Flatten<[...F, ...Rest]>
    : [F, ...Flatten<Rest>]
  : [];

// 另一种写法
type Flatten<T extends unknown[]> = T extends [infer F, ...infer R]
  ? [...(F extends unknown[] ? Flatten<F> : [F]), ...Flatten<R>]
  : [];

知识点

要将多维元组变成一维元组,需要判断元组的每一项是不是元组

  1. 在元组中,通过 infer F 取出第一项,剩余的放在 ...infer Rest
  2. 判断 F 是不是元组,如果是元组,通过递归调用 Flatten,将第一项打平,同时将 Rest 也打平
  • 因为 ...infer Rest 将元组剩余部分升维了
  1. 如果只是因为降维,那使用 ...Rest 就行的,但这里为什么要使用 ...Flatten<Rest>
  • 因为 Rest 是元组,元组就要同步进行打平
  1. 回到第二步,如果 F 不是元组,就将 F 作为元组的第一项,剩余的部分接着打平 Fletten<Rest>

ps:true 分支处理 [[1], [2, 3, [4], 5] 情况,false 分支处理 [1, [2, 3, [4], 5]]

方案二

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

知识点

思路:如果不是元组,则将这个类型变成元组

  1. 先判断的 T 是不是空元组,如果是[],直接返回 []
  2. 如果 T 不是空元组,取出第一项 F 和剩余项 Rest,分别打平
  3. 递归中的 false 分支最终会反应到 true 分支中

ps:此方案有两个问题:

  • 不能限制泛型 T 的类型
  • 传入的不是元组,将会输出会将这个类型变成元组,而不是报错,例如:Flatten<"tuple"> => ["tuple"]

方法三

type Flatten<T> = T extends unknown[]
  ? T extends [infer A, ...infer R]
    ? [...Flatten<A>, ...Flatten<R>]
    : []
  : [T];

知识点

和方法二的判断逻辑刚好相反,也存在同样的问题

  1. 先判断 T 是不是任意类型的元组
  • 如果是元组,则将它打平
  • 如果不是元组,则将这个类型变成元组

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions