-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
Description
题目
实现 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>]
: [];
知识点
要将多维元组变成一维元组,需要判断元组的每一项是不是元组
- 在元组中,通过
infer F
取出第一项,剩余的放在...infer Rest
中 - 判断
F
是不是元组,如果是元组,通过递归调用Flatten
,将第一项打平,同时将Rest
也打平
- 因为
...infer Rest
将元组剩余部分升维了
- 如果只是因为降维,那使用
...Rest
就行的,但这里为什么要使用...Flatten<Rest>
- 因为
Rest
是元组,元组就要同步进行打平
- 回到第二步,如果
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];
知识点
思路:如果不是元组,则将这个类型变成元组
- 先判断的
T
是不是空元组,如果是[]
,直接返回[]
- 如果
T
不是空元组,取出第一项F
和剩余项Rest
,分别打平 - 递归中的
false
分支最终会反应到true
分支中
ps:此方案有两个问题:
- 不能限制泛型
T
的类型 - 传入的不是元组,将会输出会将这个类型变成元组,而不是报错,例如:
Flatten<"tuple"> => ["tuple"]
方法三
type Flatten<T> = T extends unknown[]
? T extends [infer A, ...infer R]
? [...Flatten<A>, ...Flatten<R>]
: []
: [T];
知识点
和方法二的判断逻辑刚好相反,也存在同样的问题
- 先判断
T
是不是任意类型的元组
- 如果是元组,则将它打平
- 如果不是元组,则将这个类型变成元组