awesome-typescript
awesome-typescript copied to clipboard
「重学TS 2.0 」TS 练习题第四十三题
实现一个 Permutation
工具类型,当输入一个联合类型时,返回一个包含该联合类型的全排列类型数组。具体的使用示例如下所示:
type Permutation<T, K=T> = // 你的实现代码
// ["a", "b"] | ["b", "a"]
type P0 = Permutation<'a' | 'b'> // ['a', 'b'] | ['b' | 'a']
// type P1 = ["a", "b", "c"] | ["a", "c", "b"] | ["b", "a", "c"]
// | ["b", "c", "a"] | ["c", "a", "b"] | ["c", "b", "a"]
type P1 = Permutation<'a' | 'b' | 'c'>
请在下面评论你的答案
type Permutation<T, K = T> = [T] extends [never] ? [] : K extends K ? [K, ...Permutation<Exclude<T, K>>] : never
// 实现一个 Permutation 工具类型,当输入一个联合类型时,返回一个包含该联合类型的全排列类型数组。具体的使用示例如下所示:
type Om<T, I> = T extends I ? never : T;
type Test<T extends any[], F, G = F> = T extends any[]
? F | 1 extends 1
? T
: F extends any
? Test<[...T, F], Om<G, F>>
: T
: T;
type Permutation<T> = Test<[], T>;
// ["a", "b"] | ["b", "a"]
type P0 = Permutation<"a" | "b">; // ['a', 'b'] | ['b' | 'a']
// type P1 = ["a", "b", "c"] | ["a", "c", "b"] | ["b", "a", "c"]
// | ["b", "c", "a"] | ["c", "a", "b"] | ["c", "b", "a"]
type P1 = Permutation<"a" | "b" | "c">
type Permutation<T, K = T> = [T] extends [never] ? [] : T extends K ? [ T, ...Permutation<Exclude<K, T>> ] : never // 你的实现代码
// ["a", "b"] | ["b", "a"] type P0 = Permutation<'a' | 'b'> // ['a', 'b'] | ['b' , 'a'] // type P1 = ["a", "b", "c"] | ["a", "c", "b"] | ["b", "a", "c"] // | ["b", "c", "a"] | ["c", "a", "b"] | ["c", "b", "a"] type P1 = Permutation<'a' | 'b' | 'c'>
//* 实现一个 Permutation 工具类型,当输入一个联合类型时,返回一个包含该联合类型的全排列类型数组。
type IsNever<T> = [T] extends [never] ? true : false;
type Permutation<T extends string | number | symbol> = {
[index in T]: IsNever<Exclude<T,index>> extends true ? [index] : [index, ...Permutation<Exclude<T ,index>>]
}[T];
type PP = Permutation<'a'>
// ["a", "b"] | ["b", "a"]
type P0 = Permutation<'a' | 'b'> // ['a', 'b'] | ['b' | 'a']
// type P1 = ["a", "b", "c"] | ["a", "c", "b"] | ["b", "a", "c"]
// | ["b", "c", "a"] | ["c", "a", "b"] | ["c", "b", "a"]
type P1 = Permutation<'a' | 'b' | 'c'>
type Permutation<T, K = T> = [T] extends [never] ? [] : K extends K ? [K, ...Permutation<Exclude<T, K>>] : never
初看有些看不懂, 因此详细解释一下这位老哥的解法
// 1. 通过extends语法来对T类型中的或值的每一个值进行遍历
// 如果不理解的可以参考下面的例子:
// type TTT = ['a' | 'b'] extends ['a'] | ['b'] ? true : false // true
// 2. 遍历之后再对后续递归需要使用的K进行遍历(主要是起到排除当前T中的key的效果)
// 同时我们也知道, n个不重复值全排列的值为n的阶乘
// 也就是说我们需要在遍历的时候一直排除当前值, 遍历剩余值即可
// K extends K则是对当前递归场景下的所有key的遍历
// 然后最后, 递归处理剩余的参数即可, 期间使用了扩展运算符来对多维数组进行摊平
// 例如: 对于 'a' | 'b' | 'c' 来说, 会这样产生值
// ['a', ...['b', ...['c']]], ['a', ...['c', ...['b']]] ...
// 完成解构之后, 便成为了期望的 ['a', 'b', 'c'], ['a', 'c', 'b'] ...
type Permutation<T, K = T> = [T] extends [never] ? [] : K extends K ? [K, ...Permutation<Exclude<T, K>>] : never
type Permutation<T, K=T> = T extends K
?[T,...Permutation<K,Exclude<K,T>>]
:[]
这个实现看着也可以,不知有没有什么弊端
type Permutation<T, K = T>
= [T] extends [never]
? []
: K extends any
? [K, ...Permutation<Exclude<T, K>>]
: never
// ["a", "b"] | ["b", "a"]
type P0 = Permutation<"a" | "b">;
// type P1 = ["a", "b", "c"] | ["a", "c", "b"] | ["b", "a", "c"]
// | ["b", "c", "a"] | ["c", "a", "b"] | ["c", "b", "a"]
type P1 = Permutation<"a" | "b" | "c">;
type Permutation<T, K = T>
= T extends any
? Exclude<K, T> extends never
? [T]
: [T, ...Permutation<Exclude<K, T>>]
: never
type Permutation<T, K = T>
= T extends any
? Exclude<K, T> extends never
? [T]
: [T, ...Permutation<Exclude<K, T>>]
: never
type Permutation<T, K = T> = [T] extends [never] ? [] : K extends K ? [K, ...Permutation<Exclude<T, K>>] : never
初看有些看不懂, 因此详细解释一下这位老哥的解法
// 1. 通过extends语法来对T类型中的或值的每一个值进行遍历 // 如果不理解的可以参考下面的例子: // type TTT = ['a' | 'b'] extends ['a'] | ['b'] ? true : false // true // 2. 遍历之后再对后续递归需要使用的K进行遍历(主要是起到排除当前T中的key的效果) // 同时我们也知道, n个不重复值全排列的值为n的阶乘 // 也就是说我们需要在遍历的时候一直排除当前值, 遍历剩余值即可 // K extends K则是对当前递归场景下的所有key的遍历 // 然后最后, 递归处理剩余的参数即可, 期间使用了扩展运算符来对多维数组进行摊平 // 例如: 对于 'a' | 'b' | 'c' 来说, 会这样产生值 // ['a', ...['b', ...['c']]], ['a', ...['c', ...['b']]] ... // 完成解构之后, 便成为了期望的 ['a', 'b', 'c'], ['a', 'c', 'b'] ... type Permutation<T, K = T> = [T] extends [never] ? [] : K extends K ? [K, ...Permutation<Exclude<T, K>>] : never
这位老哥已经解析的很好了,补充下最前面
[T] extends [never]
是干嘛的?
因为递归调用,参数T 就是上一轮的 Exclude<T, K>
, 那么就可能会出现 Exclude<'a', 'a'>
即 never
的情况,[T] extends [never]
就是判断T是否为never, 是的话返回一个空数组即可。