持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
中等
AllCombinations
// 将字符串中的每个值使用 | 组合成联合类型
type String2Union<S extends string> =
S extends `${infer C}${infer R}`
? C | String2Union<R>
: never;
type AllCombinations<
S extends string,
U extends string = String2Union<S>,
> = [U] extends [never]
? ''
: '' | { [K in U]: `${K}${AllCombinations<never, Exclude<U, K>>}` }[U];
/*
使用示例:
'' | 'A' | 'B' | 'C' | 'AB' | 'AC' | 'BA' | 'BC' | 'CA'
| 'CB' | 'ABC' | 'ACB' | 'BAC' | 'BCA' | 'CAB' | 'CBA'
*/
type AllCombinations_ABC = AllCombinations<'ABC'>;
答案参考自解答区👍最多的
通过 case 来分析类型的执行过程,进行理解:
Expect<
Equal<
AllCombinations<'ABC'>,
'' | 'A' | 'B' | 'C' | 'AB' | 'AC' | 'BA' | 'BC' | 'CA' | 'CB' |
'ABC' | 'ACB' | 'BAC' | 'BCA' | 'CAB' | 'CBA'
>
1. 代入到类型中 :
type AllCombinations<'ABC', 'A' | 'B' | 'C'> =
['A' | 'B' | 'C'] extends [never] // 条件不成立
? ''
// 走到这
: '' |
{
[K in 'A' | 'B' | 'C']: `${K}${AllCombinations<never, Exclude<U, K>>}`
}['A' | 'B' | 'C'];
2. 以'A'为例,看看该键对应的值:
// 代入到类型当中:
{
A: `A${AllCombinations<never, 'B' | 'C'>}`
}
2.1 分析AllCombinations<never, 'B' | 'C'>:
type AllCombinations<never, 'B' | 'C'> =
['B' | 'C'] extends [never] // 条件不成立
? ''
// 走到这
: '' |
{
[K in 'B' | 'C']: `${K}${AllCombinations<never, Exclude<U, K>>}`
}['B' | 'C'];
3. 这次以'B'为例,则其对应的值为:
// 代入到类型当中:
{
B: `B${AllCombinations<never, 'C'>}`
}
3.1 代入类型AllCombinations<never, 'C'>:
type AllCombinations<never, 'C'> =
['C'] extends [never] // 条件不成立
? ''
// 走到这,就到底了
: '' |
{
[K in 'C']: `${K}${AllCombinations<never, nerver>}`
}['C'];
// 则结果为:
'' | {
// 由于 AllCombinations 一开始对 nerver 类型进行了处理
// 所以返回结果为 ''
C: 'C'
}['C']
// 最终结果:
'' | 'C'
根据 3.1 的最终结果,回到 2.1则有:
// 在字符串模板中,A 与联合类型进行拼接
// 则 A 会与联合类型中的每个类型进行拼接
{
B: `B${'' | 'C'}`
}
// B 的最终结果:
{
B: 'B' | 'BC'
}
// C 的处理逻辑跟 B 是一样的
'' | {
B: 'B' | 'BC',
C: 'C' | 'CB'
}['B' | 'C']
// 所以最终结果为:
'' | 'B' | 'BC' | 'C' | 'CB'
根据上面的结果,再回到第 2 步:
// A 对应的值处理完毕:
{
A: `A${'' | 'B' | 'BC' | 'C' | 'CB'}`
}
// 根据字符串模板的特性,A 的最终结果为:
{
A: 'A' | 'AB' | 'ABC' | 'AC' | 'ACB'
}
// 最终结果:
'' |
{
A: 'A' | 'AB' | 'ABC' | 'AC' | 'ACB',
// 下面这些跟 A 的处理逻辑一样
B: 'B' | 'BA' | 'BAC' | 'BC' | 'BCA',
C: 'C' | 'CA' | 'CAB' | 'CB' | 'CBA',
}['A' | 'B' | 'C']
// 最终结果:
'' |
'A' | 'AB' | 'ABC' | 'AC' | 'ACB'
'B' | 'BA' | 'BAC' | 'BC' | 'BCA'
'C' | 'CA' | 'CAB' | 'CB' | 'CBA'
总结
- 首先将字符串
S变为一个联合类型,通过 in 遍历,对每个字符进行处理 - 主要是利用模板字符串的特性,来产生每个可能性的字符串拼接组合
Greater Than(大于)
// 创建一个长度为 T 的元组
type Number2Tuple<T, R extends number[] = []> =
R['length'] extends T
? R
: Number2Tuple<T, [...R, 0]>;
type GreaterThan<T extends number, U extends number, Arr = Number2Tuple<T>> =
Arr extends [number, ...infer E]
?
E['length'] extends U
? true
: GreaterThan<T, U, E>
: false;
// 使用示例
GreaterThan<2, 1> // should be true
GreaterThan<10, 100> //should be false
Number2Tuple<T>用于创建一个长度为T的元组:
// 相当于 type A = [0, 0, 0]
type A = Number2Tuple<3>
执行流程如下: