题目
实现联合类型的全排列,将联合类型转换成所有坑呢的全排列数组的联合类型。
type perm = Permutation<'A' | 'B' | 'C'>;
// ['A', 'B', 'C'] | ['A', 'C', 'B']
| ['B', 'A', 'C'] | ['B', 'C', 'A']
| ['C', 'A', 'B'] | ['C', 'B', 'A']
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<boolean>, [false, true] | [true, false]>>,
Expect<Equal<Permutation<never>, []>>
]
解答区
type Permutation<T> = any
答案
type Permutation<T, K=T> = [T] extends [never]
? []
: K extends K
? [K, ...Permutation<Exclude<T, K>>]
: never
解题思路
看题目给出来的例子,第一个和最后一个还是比较简单的。
也就是
当只有一个参数,且是字符串的时候,就直接输出自己的数组这种案例;当只有一个参数,且是never的话,直接输出一个空数组。
那直接写成:
type Permutation<T> = T extends never ? [] : [T]
这样可以吗?我们可以看到结果如下:
只有第一种情况红色波浪线去除了,说明验证成功,那么最后一种情况never为什么还是不通过呢?我们来检验一下。
当我们的写法为T extends never ? [] : XX这种写法时,type a = Permutation<never> 得出的结果直接是type a = never, 假设一下:“只要这个参数传进去是never,那么得到的结果就是never?”显然不是,不是参数变量传了never,返回来的结果就never。下面这个举例可以推翻。也就是直接返回'a', 结果得到的就是'a'。
那么再来假设一下:“当 变量 extends never的时候,直接返回never?”
由这个举证可以看出,“当变量 extends never时,也就是 T extends never 时, 结果直接返回never”。这个例子就是也不走'a' ,也 不走'b',而是 T extends never 直接返回了never。为什么呢?我们来看一下。
第一点、 T extends never 直接返回never
IsNeverType 需要这样实现:
type IsNeverType<T> = T extends never ? true : never
// typescript 把 `never` 当成一个空的联合值, 所以 T extends never 这个结果最后是never,既不是true也不是false。所以我们要改动一些写法,让这个T能够被捕获到,下面👇这种写法就能轻松解决这个问题。
// 换成这种写法,当T为never时,可以被捕获到。
// 将`T`放入元组: [T]
type IsNeverType<T> = [T] extends [never] ? true : never
// 或者把T转成数组: T[]
type IsNeverType<T> = T[] extends never[] ? true ; never
第二点、K extends K
现在传参类型当中定义一个K类型,这个K就是等于T。
类型联合在条件上分布,也就是说:联合类型 'a' | 'b' | 'c' 会被递归循环 'a'、'b'、'c'三次。
如果 K extends K 就 [K, ...Permutation<Exclude<T, K>>]
type P = Permutation;
type X = Exclude
// 记住 P<never> => []
来看一下当传参联合类型为 : P<1 | 2 | 3>, [K, ...Permutation<Exclude<T, K>>]这一段代码发生了什么
| 循环 | T | K in K extends K | X<T, K> | [K, ...P<X<T, K>>] | 结果 |
|---|---|---|---|---|---|
| 1 | 1|2|3 | 1 | 2|3 | [1, ...P<2 | 3>] | |
| 1.1 | 2|3 | 2 | 3 | [1, 2, ...P<3>] | |
| 1.1.1 | 3 | 3 | never | [1, 2, 3, ...[]] | [1, 2, 3] |
| 1.2 | 2|3 | 3 | 2 | [1, 3 ...P<2>] | |
| 1.2.1 | 2 | 2 | never | [1, 3, 2, ...[]] | [1, 3, 2] |
| 2 | 1|2|3 | 2 | 1|3 | [2, ...P<1 | 3>] | |
| 2.1 | 1|3 | 1 | 3 | [2, 1, ...P<3>] | |
| 2.1.1 | 3 | 3 | never | [2, 1, 3, ...[]] | [2, 1, 3] |
| 2.2 | 1|3 | 3 | 1 | [2, 3 ...P<1>] | |
| 2.2.2 | 1 | 1 | never | [2, 3, 1, ...[]] | [2, 3, 1] |
| 3 | 1|2|3 | 3 | 1|2 | [3, ...P<1 | 2>] | |
| 3.1 | 1|2 | 1 | 2 | [3, 1, ...P<2>] | |
| 3.1.1 | 2 | 2 | never | [3, 1, 2, ...[]] | [3, 1, 2] |
| 3.2 | 1|2 | 2 | 1 | [3, 2, ...P<1>] | |
| 3.2.2 | 1 | 1 | never | [3, 2, 1, ...[]] | [3, 2, 1] |
所以P<1 | 2 | 3>最终有的组合是: [1, 2, 3] | [1, 3, 2] | [2, 1, 3] | [2, 3, 1] | [3, 1, 2] | [3, 2, 1]
最终答案type Permutation 可以实现联合类型的全排列:
type Permutation<T, K=T> = [T] extends [never]
? []
: K extends K
? [K, ...Permutation<Exclude<T, K>>]
: never
至此,此中等题目之实现Permutation(实现联合类型的全排列)完成!