[Typescript] 110. Hard - Union to Tuple

Implement a type, UnionToTuple, that converts a union to a tuple.

As we know, union is an unordered structure, but tuple is an ordered, which implies that we are not supposed to preassume any order will be preserved between terms of one union, when unions are created or transformed.

Hence in this challenge, any permutation of the elements in the output tuple is acceptable.

Your type should resolve to one of the following two types, but NOT a union of them!

UnionToTuple<1>           // [1], and correct
UnionToTuple<'any' | 'a'> // ['any','a'], and correct

or

UnionToTuple<'any' | 'a'> // ['a','any'], and correct

It shouldn't be a union of all acceptable tuples...

UnionToTuple<'any' | 'a'> // ['a','any'] | ['any','a'], which is incorrect

And a union could collapes, which means some types could absorb (or be absorbed by) others and there is no way to prevent this absorption. See the following examples:

Equal<UnionToTuple<any | 'a'>,       UnionToTuple<any>>         // will always be a true
Equal<UnionToTuple<unknown | 'a'>,   UnionToTuple<unknown>>     // will always be a true
Equal<UnionToTuple<never | 'a'>,     UnionToTuple<'a'>>         // will always be a true
Equal<UnionToTuple<'a' | 'a' | 'a'>, UnionToTuple<'a'>>         // will always be a true

 

/* _____________ Your Code Here _____________ */

// 参考:https://github.com/type-challenges/type-challenges/issues/10191

// 1. 将联合类型转换成对应的函数交叉类型 (arg的参数是函数,返回的类型才是交叉类型,其他的都是never)
type UnionToIntersectionFn<U> = (U extends any ? (arg: () => U) => void : never) extends (arg: infer I) => void ? I : never;

// 2. 获取联合类型的最后一个类型
// (() => "a") & (() => "b") & (() => "c")
// 在获取函数的返回值上,函数重载和函数交叉类型是一样的
type GetLastUnion<U> = UnionToIntersectionFn<U> extends () => infer I ? I : never;

// 3. 联合类型转换为元组
type UnionToTuple<U, Last = GetLastUnion<U>> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, Last>>, Last];
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'

type ExtractValuesOfTuple<T extends any[]> = T[keyof T & number]

type cases = [
  Expect<Equal<UnionToTuple<'a' | 'b'>['length'], 2>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a' | 'b'>>, 'a' | 'b'>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a'>>, 'a'>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any>>, any>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<undefined | void | 1>>, void | 1>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any | 1>>, any | 1>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<any | 1>>, any>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'d' | 'f' | 1 | never>>, 'f' | 'd' | 1>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<[{ a: 1 }] | 1>>, [{ a: 1 }] | 1>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<never>>, never>>,
  Expect<Equal<ExtractValuesOfTuple<UnionToTuple<'a' | 'b' | 'c' | 1 | 2 | 'd' | 'e' | 'f' | 'g'>>, 'f' | 'e' | 1 | 2 | 'g' | 'c' | 'd' | 'a' | 'b'>>,
]

 

posted @ 2022-11-19 00:52  Zhentiw  阅读(39)  评论(0编辑  收藏  举报