题目描述
实现联合类型的全排列,将联合类型转换成所有可能的全排列数组的联合类型。
type perm = Permutation<'A' | 'B' | 'C'>; // ['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']
题解
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'
type cases = [
Expect<Equal<Permutation<'A'>, ['A']>>,
Expect<Equal<Permutation<'A' | 'B' | 'C'>, ['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']>>,
Expect<Equal<Permutation<'B' | 'A' | 'C'>, ['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']>>,
Expect<Equal<Permutation<boolean>, [false, true] | [true, false]>>,
Expect<Equal<Permutation<never>, []>>,
]
// ============= Your Code Here =============
type Permutation<T, Acc = T> =
[T] extends [never]
? []
: Acc extends any
? [Acc, ...Permutation<Exclude<T, Acc>>]
: never;
引入泛型
引入泛型Acc,Acc是一个累积器,默认值为T,用来存储当前的排列
条件类型
type Permutation<T, Acc = T> =
[T] extends [never]
? []
: Acc extends any
? [Acc, ...Permutation<Exclude<T, Acc>>]
: never;
- 如果
T是never,返回一个空数组[] - 如果
T不是never,使用Acc extends any进行分布式条件判断,将条件应用到联合类型的每个成员上 [Acc, ...Permutation<Exclude<T, Acc>>]- 将当前的成员添加到结果中
- 通过
Exclude<T, Acc>排除已经选取的元素,再递归调用Permutation对剩余元素进行排列,添加到数组后面
Case 推导思路
Case 1: Permutation<'A' | 'B' | 'C'>
-
初始状态:
T是'A' | 'B' | 'C',Acc默认是'A' | 'B' | 'C'
-
递归步骤:
-
首先检查
[T] extends [never],此条件不成立,进入下一个条件分支 -
接着,由于
Acc是一个联合类型,TypeScript 的分布式条件判断会对Acc的每个成员进行单独处理:-
当
Acc是'A'时,调用Permutation<Exclude<'A' | 'B' | 'C', 'A'>>,得出Permutation<'B' | 'C'>。此时,T变为'B' | 'C',Acc默认是'B' | 'C'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'B'时,调用Permutation<Exclude<'B' | 'C', 'B'>>,得出Permutation<'C'>。此时,T变为'C',Acc默认是'C'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'C'时,调用Permutation<Exclude<'C', 'C'>>,得出Permutation<never>。此时,T是never,Acc默认是never -
[T] extends [never]成立,返回[] -
最终得到
['A', 'B', 'C']作为其中一个排列
-
-
-
当
Acc是'C'时,调用Permutation<Exclude<'B' | 'C', 'C'>>,得出Permutation<'B'>。此时,T变为'B',Acc默认是'B'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'B'时,调用Permutation<Exclude<'B', 'B'>>,得出Permutation<never>。此时,T是never,Acc默认是never -
[T] extends [never]成立,返回[] -
最终得到
['A', 'C', 'B']作为其中一个排列
-
-
-
-
-
当
Acc是'B'时,调用Permutation<Exclude<'A' | 'B' | 'C', 'B'>>,得出Permutation<'A' | 'C'>。此时,T变为'A' | 'C',Acc默认是'A' | 'C'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'A'时,调用Permutation<Exclude<'A' | 'C', 'A'>>,得出Permutation<'C'>。此时,T变为'C',Acc默认是'C'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'C'时,调用Permutation<Exclude<'C', 'C'>>,得出Permutation<never>。此时,T是never,Acc默认是never -
[T] extends [never]成立,返回[] -
最终得到
['B', 'A', 'C']作为其中一个排列
-
-
-
当
Acc是'C'时,调用Permutation<Exclude<'A' | 'C', 'C'>>,得出Permutation<'A'>。此时,T变为'A',Acc默认是'A'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'A'时,调用Permutation<Exclude<'A', 'A'>>,得出Permutation<never>。此时,T是never,Acc默认是never -
[T] extends [never]成立,返回[] -
最终得到
['B', 'C', 'A']作为其中一个排列
-
-
-
-
-
当
Acc是'C'时,调用Permutation<Exclude<'A' | 'B' | 'C', 'C'>>,得出Permutation<'A' | 'B'>。此时,T变为'A' | 'B',Acc默认是'A' | 'B'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'A'时,调用Permutation<Exclude<'A' | 'B', 'A'>>,得出Permutation<'B'>。此时,T变为'B',Acc默认是'B'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'B'时,调用Permutation<Exclude<'B', 'B'>>,得出Permutation<never>。此时,T是never,Acc默认是never -
[T] extends [never]成立,返回[] -
最终得到
['C', 'A', 'B']作为其中一个排列
-
-
-
当
Acc是'B'时,调用Permutation<Exclude<'A' | 'B', 'B'>>,得出Permutation<'A'>。此时,T变为'A',Acc默认是'A'-
[T] extends [never]不成立,进入下一个条件分支 -
对于新的
Acc的每个成员:-
当
Acc是'A'时,调用Permutation<Exclude<'A', 'A'>>,得出Permutation<never>。此时,T是never,Acc默认是never -
[T] extends [never]成立,返回[] -
最终得到
['C', 'B', 'A']作为其中一个排列
-
-
-
-
-
-
最终,Permutation<'A' | 'B' | 'C'>的结果是['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']