# 730-联合转元组
# 题目描述
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
# 分析
这个题目,也是经典中的经典了。
元组转联合,元组转对象,元组转交叉,都做过了的你,相信碰到联合转元组,依旧一脸懵逼。因为确实还要用到一些不常见的知识点:
type Intersepted = (() => 'a') & (() => 'b') & (() => 'c');
type Last = Intersepted extends () => infer R ? R : never; // 'c'
也就是,当几个函数交叉后的返回值,就是最后一个交叉的返回值。
通过这个方法,可以从交叉类型中获取最后一个元素。
那么借助 元组转交叉,就可以推断出最后一个联合元素,接下来只需要不断递归排除了最后一个元素的联合类型,就可以得到结果。
# 题解
// [元组转交叉](/hard/55-UnionToIntersection.md)
type UnionToIntersection<T> = (
T extends any ? (arg: T) => any : never
) extends (arg: infer X) => any
? X
: never;
//
type LastUnion<T> = UnionToIntersection<
T extends any ? () => T : never
> extends () => infer R
? R
: never;
type UnionToTuple<T> = [T] extends [never]
? []
: // 获取最后一个元素,并递归排除了最后一个元素的联合类型即可
[LastUnion<T>, ...UnionToTuple<Exclude<T, LastUnion<T>>>];
# 知识点
- 元组转交叉
- 函数交叉类型的返回值,是最后一个函数的返回值