例如,我有一个类型:
type abc = 'a' | 'b' | 'c';
如何制作一个在编译时包含联合所有元素的元组类型?
type t = ['a','b', 'c'];
最佳答案
免责声明:不要这样做!!如果有人告诉你使用他们在这个答案中找到的代码来做任何事情,除了证明为什么这是一个坏主意,跑开!
从元组类型转换为联合类型很容易;例如,参见 this question .但恰恰相反,从联合转换为元组是您不应该尝试做的那些真正糟糕的想法之一。 (请参阅 microsoft/TypeScript#13298 以获取讨论和规范答案)让我们先做,然后再自责:
// oh boy don't do this
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type LastOf<T> =
UnionToIntersection<T extends any ? () => T : never> extends () => (infer R) ? R : never
// TS4.0+
type Push<T extends any[], V> = [...T, V];
// TS4.1+
type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> =
true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>
type abc = 'a' | 'b' | 'c';
type t = TuplifyUnion<abc>; // ["a", "b", "c"]
那种工作,但我真的真的真的建议不要将它用于任何官方目的或在任何生产代码中。原因如下:
您不能依赖联合类型的排序。它是编译器的一个实现细节;自
X | Y
等同于Y | X
,编译器可以随意将一个更改为另一个。有时确实如此:type TypeTrue1A = TuplifyUnion<true | 1 | "a">; // [true, 1, "a"] 🙂 type Type1ATrue = TuplifyUnion<1 | "a" | true>; // [true, 1, "a"]!! 😮
所以真的没办法保序。并且请不要假设输出至少总是上面的
[true, 1, "a"]
;不能保证。这是一个实现细节,因此特定输出可以从一个版本的 TypeScript 更改为下一个版本,或者从一个代码编译更改为下一个。这在某些情况下确实会发生:例如,编译器缓存联合;看似无关的代码可能会影响将哪个联合排序放入缓存,从而影响哪个排序。订单不只是不可靠。您可能对编译器将什么视为并集以及何时折叠或展开不满意。
“一个” | string
将被压缩为string
,而boolean
实际上是 expanded 为false |真
:type TypeAString = TuplifyUnion<"a" | string>; // [string] type TypeBoolean = TuplifyUnion<boolean>; // [false, true]
因此,如果您计划保留一些现有元素,则应该停止计划。没有通用的方法可以让元组在不丢失此信息的情况下进入联合并返回。
没有受支持的方法来遍历通用联合。我用的招数全被滥用conditional types .首先我转换一个联合
A |乙 | C
变成函数的联合,如()=>A | ()=>B | ()=>C
,然后使用 intersection inference trick将该函数并集转换为函数的交集,例如()=>A & ()=>B & ()=>C
,它被解释为单个 overloaded函数类型,并使用条件类型提取返回值仅获取 last 重载。所有这些疯狂最终都以A | 结束。乙 | C
并只提取一个成分,可能是C
。然后你必须把它推到你正在构建的元组的末尾。现在 TypeScript 4.1 引入的原因不多了 recursive conditional types ,但递归条件类型对编译器的负担比您想要的要大,并且递归限制较浅。因此,如果您有超过 20 个元素的联合,或者其类型本身以某种方式递归的联合,您可能会遇到一些性能或编译问题。
就这样吧。你可以做,但不要做。 (如果你确实这样做了,如果有什么东西爆炸了,不要怪我。💣)希望对你有帮助。祝你好运!
关于typescript - 如何将联合类型转换为元组类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55127004/