携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
中等
Chunk(lodash.chunk)
type Chunk<T extends any[], U extends number, A extends any[] = []> =
T extends [infer F, ...infer E]
? A['length'] extends U
? [A, ...Chunk<E, U, [F]>]
: Chunk<E, U, [...A, F]>
: A extends [] ? [] : [A]
// 使用示例
type exp1 = Chunk<[], 1> // 结果为 []
type exp3 = Chunk<[1, 2, 3], 1> // 结果为 [[1], [2], [3]]
直接通过一个 case 来了解整个过程:
Expect<
Equal<
Chunk<[1, 2, 3], 1>,
[[1], [2], [3]]
>
>
1. 代入到类型中:
type Chunk<[1, 2, 3], 1, []> =
[1, 2, 3] extends [infer F, ...infer E] // 条件成立
? 0 extends 1 // 条件不成立
? [A, ...Chunk<E, U, [F]>]
// 会走到这,结果如下:
: Chunk<[2, 3], 1, [1]>
: A extends [] ? [] : [A]
2. 代入结果Chunk<[2, 3], 1, [1]>:
type Chunk<[2, 3], 1, [1]> =
[2, 3] extends [infer F, ...infer E] // 条件成立
? 1 extends 1 // 条件成立
// 会走到这,结果如下:
? [[1], ...Chunk<[3], 1, [2]>]
: Chunk<E, U, [...A, F]>
: A extends [] ? [] : [A]
3. 根据第 2 步的结果代入类型Chunk<[3], 1, [2]>:
type Chunk<[3], 1, [2]> =
[3] extends [infer F, ...infer E] // 条件成立
? 1 extends 1 // 条件成立
// 会走到这,结果如下:
? [[2], ...Chunk<[], 1, [3]>]
: Chunk<E, U, [...A, F]>
: A extends [] ? [] : [A]
4. 根据第 3 步的结果代入类型Chunk<[], 1, [3]>]:
type Chunk<[], 1, [3]> =
[] extends [infer F, ...infer E] // 条件不成立
? A['length'] extends U
? [A, ...Chunk<E, U, [F]>]
: Chunk<E, U, [...A, F]>
// 会走到这,结果为
: [3] extends [] ? [] : [[3]]
将所有结果进行代入:
// 第 3 步结果
[[2], ...[[3]]]
// 等于
[[2], [3]]
// 第 2 步结果
[[1], ...[[2], [3]]]
// 最终结果等于
[[1], [2], [3]]
我的解题思路如图:
Fill(Array.fill())
// 创建长度为 N 的数组
type BuildArray<N extends number, T extends any[] = []> = T['length'] extends N ? T : BuildArray<N, [...T, 0]>;
// 给元组 T 添加一个元素,再返回长度
type AddOne<T extends number> = [...BuildArray<T>, 0]['length']
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
U extends unknown[] = [],
> =
T extends [infer First, ...infer Rest]
?
Start extends End
? [...U, ...T]
: U['length'] extends Start
? Fill<Rest, N, AddOne<Start> & number, End, [...U, N]>
: Fill<Rest, N, Start, End, [...U, First]>
: U
// 使用示例
Fill<[], 0> // []
Fill<[1, 2, 3], 0> // [0, 0, 0]
Fill<[1, 2, 3], true, 1, 3> // [1, true, true]
答案参考于解答区
- 其中占位类型 U 是用来存储迭代中处理的元素,
BuildArray与AddOne只是工具类型。 - 当当前索引位于
Start与End之间时,则使用N进行填充,并且Start要加 1,再继续进行迭代。 - 当
U的长度始终不等于Start时,说明Start大于T的长度。
解题思路汇总成一张图: