21220-medium-permutations-of-tuple

Back

type PermutationsOfTuple<T extends unknown[], SaveArr extends any[]=[]> = T extends [infer A, infer B, ...infer C] 
  ?PermutationsOfTuple<[B,...C],[...SaveArr,A]> | PermutationsOfTuple<[A,...C],[B,...SaveArr]>
  :[...T,...SaveArr] |[...SaveArr,...T]
  //#A넣고
  //B넣고
  //C넣고
  //a넣고
  //C넣고
  //B넣고

Solution by bananana0118 #33170

type PermutationsOfTuple<T extends unknown[], Indexes extends keyof T = keyof T & `${number}`> =
  [Indexes] extends [never] // base case
    ? []
  : {[I in Indexes]: [T[I], ...PermutationsOfTuple<T, Exclude<Indexes, I>>]}[Indexes]

Playground

Solution by teamchong #33062

type PermutationsOfTuple<
  T extends unknown[],
  C extends any[] = []
> = T extends [infer F, ...infer R]
  ?
      | [F, ...PermutationsOfTuple<R, []>]
      | ([...C, any]["length"] extends T["length"]
          ? never
          : PermutationsOfTuple<[...R, F], [...C, any]>)
  : [];

Solution by vangie #32205

提供一个解题思路

  1. 如果入参数组中都是字面量类型的话,如PermutationsOfTuple<[1, 2, 3]>,可以参考296・Permutation
type Permutation<T, K=T> = [T] extends [never] ? [] : (K extends K ? [K, ...Permutation<Exclude<T, K>>] : never);
  1. 本题还需要处理any、unkown等,则会遇到一些麻烦,比如:
type Test1 = ([any, unknown, 1])[number]; // any
type Test2 = ([1, 2, 3, 4])[number]; // 1 | 2 | 3 | 4

其中Test2才是我们想要的结果。

  1. 为了解决2中的问题,我们可以给数组中的每个元素提前包一层:
type WrapArray<T extends any[]> = T extends [infer S, ...infer O] ? [[S], ...WrapArray<O>] : [];
type Test1 = WrapArray<[any, unknown]> // [[any], [unknown]]
type Test2 = Test1[number]; // [unknown] | [any]

这样我们就可以通过联合类型的分布式计算迭代出每个元素了

  1. 接着是Exclude的处理,我们不能直接从 [any] | [unknown]中剔除[unknown],比如
type Test = Exclude<[any]|[unknown], [unknown]>; // never

但是我们可以直接通过他原本的数组剔除其中的元素,比如从[[unknown], [any], 1]中剔除[unknown]得到其他元素[[any], 1],代码如下:

type MyEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
type MyExclued<T extends any[], U> = T extends [infer S, ...infer O] ? (MyEqual<S, U> extends true ? MyExclued<O, U> : [S, ...MyExclued<O, U>]) : [];
type Test = MyExclued<[[unknown], [any], 1], [unknown]> //[[any], 1]
  1. 有了以上步骤的工具,那么我们就可以完全参照296・Permutation 的解法来处理这个问题了,整体代码如下:
type WrapArray<T extends any[]> = T extends [infer S, ...infer O] ? [[S], ...WrapArray<O>] : [];
type MyEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
type MyExclued<T extends any[], U> = T extends [infer S, ...infer O] ? (MyEqual<S, U> extends true ? MyExclued<O, U> : [S, ...MyExclued<O, U>]) : [];
type MyPermutationsOfTuple<T extends any[], U = T[number], O = U> = [U] extends [never] ? [] : (U extends U ? [U extends any[] ? U[0] : never, ...MyPermutationsOfTuple<MyExclued<T, U>>] : []);
type PermutationsOfTuple<T extends unknown[], U extends unknown[] = WrapArray<T>> = MyPermutationsOfTuple<U>;

最后别忘了一开始我们给数组中的每个元素包了一层数组,所以取值的时候取U[0]即可。

Solution by tarotlwei #31765

// [1, number, unknown] => [0, 1, 2] 拿到索引数组
type GetIndex<T extends unknown[], U extends number[] = []> = T extends [
  any,
  ...infer R
]
  ? GetIndex<R, [...U, U["length"]]>
  : U;

// [0, 1, 2] => [0, 1, 2] | [0, 2, 1] | [1, 0, 2] | [1, 2, 0] | [2, 0, 1] | [2, 1, 0] 打乱索引数组
type GetUnion<T extends number[], U = T[number], K = U> = [U] extends [never]
  ? []
  : U extends K
  ? [U, ...GetUnion<[], Exclude<K, U>>]
  : [];

// [0, 1, 2] => [1, number, unknown] 根据索引取对应项值,得到最终结果
type PermutationsOfTuple<
  T extends unknown[],
  U = GetUnion<GetIndex<T>>
> = U extends [infer F extends number, ...infer R]
  ? [T[F], ...PermutationsOfTuple<T, R>]
  : [];

type Res = PermutationsOfTuple<[1, number, unknown]>;

Solution by moonpoet #31038

// your answers
// type PermutationsOfUnion<T, U = T> =
//   [T] extends [never]
//     ? []
//     : U extends T
//       ? [U, ...PermutationsOfUnion<Exclude<T, U>>]
//       : []

type GetIndexUnion<T extends unknown[]> =
  T extends [infer _, ...infer R]
    ? R['length'] | GetIndexUnion<R>
    : never

type GetTupleByIndexUnion<T extends unknown[], U extends number, I = U> =
  [U] extends [never]
    ? []
    : I extends U
        ? [T[I], ...GetTupleByIndexUnion<T, Exclude<U, I>>]
        : []

type PermutationsOfTuple<T extends unknown[]> = GetTupleByIndexUnion<T, GetIndexUnion<T>>

Solution by milletlovemouse #30946

// your answers

type InsertToArr<Left extends unknown[], S, Right extends unknown[] = []> = Left extends [...infer Rest, infer Last] ? [...Left, S, ...Right] | InsertToArr<Rest, S, [Last, ...Right]> : [S, ...Right]

type PermutationsOfTuple<T extends unknown[]> = T extends [infer First, ...infer Rest] ? InsertToArr<PermutationsOfTuple<Rest>, First> : []

Solution by Kakeru-Miyazaki #30922

type PermutationsOfTuple<T extends unknown[]> = T extends [infer F, ...infer Rest, infer L]
  ?
      | [F, ...PermutationsOfTuple<Rest>, L]
      | [L, ...PermutationsOfTuple<Rest>, F]
      | [F, L, ...PermutationsOfTuple<Rest>]
      | [L, F, ...PermutationsOfTuple<Rest>]
      | [...PermutationsOfTuple<Rest>, F, L]
      | [...PermutationsOfTuple<Rest>, L, F]
  : T;

Solution by leejaehyup #30877

type Insert<
  T extends unknown[],
  U
> = 
T extends [infer F,...infer L]
  ? [F,U,...L] | [F,...Insert<L,U> ] 
  : [U]

type PermutationsOfTuple<
  T extends unknown[],
  R extends unknown[] = []
> = 
T extends [infer F,...infer L]?
  PermutationsOfTuple<L,Insert<R,F> | [F,...R] >
  :R

Solution by jiangshanmeta #29713

type PermutationsOfTuple<T extends unknown[], Prev extends unknown[] = []> = T extends [infer First, ...infer Rest]
  ? [First, ...PermutationsOfTuple<[...Prev, ...Rest]>] | (Rest extends [] ? never : PermutationsOfTuple<Rest, [...Prev, First]>)
  : []

Solution by Sun79 #29657