javascript - 在 Typescript 中遍历可变参数元组
问题描述
编辑:此功能作为 TypeScript 4.1 的一部分提供,如 @jcalz 提到的。
我想做一个接受元组并遍历它的泛型类型。我的第一种方法是使用递归,但我得到了一个Type alias 'YourOperator' circularly references itself.
. 这是我尝试过的最简单的例子
type VariadicAnd<T extends any[]> = T extends [infer Head, ...infer Tail] ? Head & VariadicAnd<Tail> : unknown
在我的具体情况下,我进一步想Head
通过将它传递给另一个泛型类型来进行转换。例如:
type SimpleTransform<T> = { wrapped: T }
type VariadicAndWithTransform<T extends any[]> = T extends [infer Head, ...infer Tail]
? SimpleTransform<Head> & VariadicAndWithTransform<Tail>
: unknown;
有趣的是,我的 IntelliSence 正在正确解析类型,但 typescript 编译器拒绝接受它。我想知道是否有另一种方法,或者是否有办法让我的递归工作。
解决方案
如上所述,在引入对递归条件类型的支持之后,您的版本在 TypeScript 4.1 及更高版本中按原样工作。
type VariadicAndWithTransform<T extends any[]> = T extends [infer F, ...infer R]
? SimpleTransform<F> & VariadicAndWithTransform<R>
: unknown; // no error
type Works = VariadicAndWithTransform<[{ a: 1 }, { b: 2 }, { c: 3 }]>;
/* type Works = SimpleTransform<{
a: 1;
}> & SimpleTransform<{
b: 2;
}> & SimpleTransform<{
c: 3;
}> */
有一些变通方法可以诱使编译器允许 4.1 之前的类型,但它们不受官方支持。如果你需要递归条件类型,你应该升级你的 TypeScript 版本。
但是对于此处所需的类型函数,您不需要递归类型。这实际上是一件好事,因为递归类型对编译器的负担更大,并且递归限制相当浅。如果你使用上面版本的VariadicAndWithTransform<T>
whereT
有几十个元素,你会看到错误,即使在 TS4.1+ 中:
type Three = [{}, {}, {}];
type Nine = [...Three, ...Three, ...Three];
type TwentySeven = [...Nine, ...Nine, ...Nine]
type UhOh = VariadicAndWithTransform<TwentySeven>; // error!
// -------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type instantiation is excessively deep and possibly infinite.
非递归版本对人类来说更难理解,但它使编译器更容易:
type VariadicAndWithTransform<T extends any[]> = {
[K in keyof T]: (v: SimpleTransform<T[K]>) => void
}[number] extends ((v: infer I) => void) ? I : never
它的工作原理是从逆变位置(例如函数的参数)的联合中推断出条件类型,类似于此问题UnionToIntersection<T>
的答案中的类型。
您可以验证它的行为是否与上面的示例相同:
type Works = VariadicAndWithTransform<[{ a: 1 }, { b: 2 }, { c: 3 }]>;
/* type Works = SimpleTransform<{
a: 1;
}> & SimpleTransform<{
b: 2;
}> & SimpleTransform<{
c: 3;
}> */
而且因为它不使用递归,所以它在处理更长的元组时没有问题:
type StillWorks = VariadicAndWithTransform<TwentySeven>;
/* type StillWorks = { wrapped: {}; } */
推荐阅读
- c# - 如何将数组作为参数传递给从 C++ 到 C# 的函数调用
- c# - 如何调整这个 wpf 按钮的大小
- javascript - 在 base64url 编码之前,是否有将 `+` 和 `/` 转换为 `-` 和 `_` 的原生 JS 方法?它是什么?
- c - 重定向标准输入和标准输出?
- c - 使用 netbeans 运行 isPrime 程序时出现截断问题
- android - 具有多个活动的问题 Google 同意 sdk (admob)
- sp - Ripleys K 绘图不正确?
- javascript - 需要在 C# 类库中包装 JavaScript API(不是 asp.net 应用程序)
- javascript - 对象集合的 React JS 状态更新
- boolean-logic - 布尔逻辑和真值表