在我对 Can Typescript Interfaces express co-occurrence constraints for properties 的回答中我生成了以下代码:
type None<T> = {[K in keyof T]?: never}
type EitherOrBoth<T1, T2> = T1 & None<T2> | T2 & None<T1> | T1 & T2
type CombinationOf<T> = T extends [infer U1, infer U2] ? EitherOrBoth<U1, U2> :
T extends [infer U1, infer U2, infer U3] ? EitherOrBoth<U1, EitherOrBoth<U2, U3>> :
T extends [infer U1, infer U2, infer U3, infer U4] ? EitherOrBoth<U1, EitherOrBoth<U2, EitherOrBoth<U3, U4>>> :
never;
type Monolith = CombinationOf<[Data1, Data2, Data3]>
目前,CombinationOf
处理类型参数的元组,最多四个元素。
虽然这可以简单地扩展,但我想知道随着 recursive conditional types 的出现是否可以,类型CombinationOf
可以用更优雅的方式表达。
因此,我的问题是:
- 我可以使用递归条件类型将类型元组(任意长度)映射到嵌套类型吗?
- 如果是这样,递归是否有深度限制? (希望这只是理论上的问题)
- 我如何向自己证明使用递归条件类型生成的新类型与我现有的代码等效?
最佳答案
在 TypeScript 4.1 中引入递归条件类型时,您应该能够定义 CombinationOf<T>
像这样:
type CombinationOf<T> =
T extends [infer U1, ...infer R] ? (
R extends [] ? never : EitherOrBoth<U1,
R extends [infer U2] ? U2 : CombinationOf<R>
>
) : never;
在这里,我尝试尽可能接近您的原始定义,而不用担心 EitherOrBoth<>
的内容。 type 应该是真正在做的事情。请注意,因为您的原始定义返回 never
当T
是一个单元素元组,这里的定义稍微复杂一些。 (我有点期望 CombinationOf<[X]>
只是 X
。但是🤷♂️)
如果T
有 0 或 1 个元素,您将得到 never
。如果有两个元素,您将得到 EitherOrBoth<U1, U2>
哪里U1
和U2
是 T
的前两个元素。否则,您会得到 EitherOrBoth<U1, CombinationOf<R>>
哪里R
是元组的其余部分/尾部 T
之后U1
.
是的,有深度限制,而且不是很深;大约 10 个级别:
type TestDepth = CombinationOf<[1, 2, 3, 4, 5, 6, 7, 8, 9]> // works for me
type TestDepthBad = CombinationOf<[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]> // error, too deep
你或许可以重写CombinationOf
看起来更像你的原始版本,它切割了元组 T
分为 3 或 4 组而不是 1 组,并增加深度限制(也许增加到 30 或 40...编辑:玩这个我似乎无法让它超过 25 左右)费用更加复杂CombinationOf
。但不确定这是否值得。
证明类型相同可以通过检查此 CombinationOf
的定义来完成和你的(我称之为 CombinationOfOrig
),或者通过构建检查器类型函数:
type IfEquals<T, U, Y = unknown, N = never> =
(<G>() => G extends T ? 1 : 2) extends
(<G>() => G extends U ? 1 : 2) ? Y : N;
type TestEqualCombinationOf<T> =
IfEquals<CombinationOfOrig<T>, CombinationOf<T>, "Same", "Oops">;
在这里,IfEquals<T, U, Y, N>
将评估为 Y
如果编译器看到 T
和U
作为相同类型,并且 N
否则。请参阅this comment in GitHub有关此类型相等运算符的更多信息。
和TestEqualCombinationOf<T>
将评估为 "Same"
如果CombinationOfOrig<T>
与 CombinationOf<T>
相同,和"Oops"
否则。以下是测试结果:
type TestEmpty = TestEqualCombinationOf<[]> // Same
type TestSingleton = TestEqualCombinationOf<[Data1]> // Same
type TestPair = TestEqualCombinationOf<[Data1, Data2]>; // Same
type TestTriple = TestEqualCombinationOf<[Data1, Data2, Data3]>; // Same
interface Data4 { four: 4 }
type TestQuadruple = TestEqualCombinationOf<[Data1, Data2, Data3, Data4]>; // Same
interface Data5 { five: 5 }
type TestQuintuple = TestEqualCombinationOf<[Data1, Data2, Data3, Data4, Data5]>; // Oops
因此,至少在实验上,对于长度不超过 4 的任何元组,这两个定义都是相同的。我实际上有点担心 TestQuintuple
是"Oops"
直到我想起原来的定义只适用于长度不超过 4 的元组。所以 "Oops"
预计。
关于typescript - 如何使用递归条件类型将类型(任意长度)的元组映射到嵌套类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63907907/