我需要向映射元组元素的函数添加类型声明 [Foo<A>, Foo<B>, ...]
到函数 () => [A, B, ...]
.我如何在 TypeScript 中实现这一点?
此示例在结构上与应用程序的相关部分类似:
interface SomethingWithAValue<T> { value: T; }
function collect(array) {
return () => array.map(a => a.value);
}
这将返回与每个对象关联的值的元组。 collect
的类型声明是什么?看起来像?
伪代码:
function collect<[SomethingWithAValue<T>...](array: [SomethingWithAValue<T>...]): () => [T...];
根据 jonrsharpe 的建议更新:
interface SomethingWithAValue<T> { value: T; }
function collect<T>(array: SomethingWithAValue<T>[]): () => T[] {
return () => array.map(a => a.value);
}
type myTupleType = [string, number];
let somethings: [SomethingWithAValue<string>, SomethingWithAValue<number>];
somethings = [{ value: 'foo' }, { value: 5 }];
let fn: () => myTupleType = collect(somethings);
这不起作用:
Argument of type '[SomethingWithAValue<string>, SomethingWithAValue<number>]' is not assignable to parameter of type 'SomethingWithAValue<string>[]'.
Types of property 'pop' are incompatible.
Type '() => SomethingWithAValue<string> | SomethingWithAValue<number>' is not assignable to type '() => SomethingWithAValue<string>'.
Type 'SomethingWithAValue<string> | SomethingWithAValue<number>' is not assignable to type 'SomethingWithAValue<string>'.
Type 'SomethingWithAValue<number>' is not assignable to type 'SomethingWithAValue<string>'.
Type 'number' is not assignable to type 'string'.
最佳答案
更新:以下答案自 TS3.1 起已过时。我相信你现在可以使用 mapped tuple types和 conditional type inference获得你想要的行为:
type ExtractValue<T extends ReadonlyArray<SomethingWithAValue<any>>> =
{ [K in keyof T]: T[K] extends SomethingWithAValue<infer V> ? V : never };
function collect<T extends ReadonlyArray<SomethingWithAValue<any>>>(
array: T
): () => ExtractValue<T> {
return () => array.map(a => a.value) as any;
}
让我们使用它...首先让我们使用辅助函数 tuple()
轻松获得元组类型,该函数接受可变数量的参数并输出一个元组(这是制作的从 TS3.0 开始可能)
type Narrowable = string | number | boolean | undefined | null | void | {};
const tuple = <T extends Narrowable[]>(...t: T) => t;
让我们看看它是否有效:
const result = collect(tuple({ value: 10 }, { value: "hey" }, { value: true }));
// const result: () => [number, string, boolean]
看起来不错!
旧答案:
没有 variadic kinds在 TypeScript 中,因此无法键入通用元组(不存在语法 [T...]
)。
作为一种变通方法,您可以为任何长度的元组提供函数重载,直到某个合理的最大值:
function collect<A, B, C, D, E>(array: [SomethingWithAValue<A>, SomethingWithAValue<B>, SomethingWithAValue<C>, SomethingWithAValue<D>, SomethingWithAValue<E>]): () => [A, B, C, D, E];
function collect<A, B, C, D>(array: [SomethingWithAValue<A>, SomethingWithAValue<B>, SomethingWithAValue<C>, SomethingWithAValue<D>]): () => [A, B, C, D];
function collect<A, B, C>(array: [SomethingWithAValue<A>, SomethingWithAValue<B>, SomethingWithAValue<C>]): () => [A, B, C];
function collect<A, B>(array: [SomethingWithAValue<A>, SomethingWithAValue<B>]): () => [A, B];
function collect<A>(array: [SomethingWithAValue<A>]): () => [A];
function collect<T>(array: SomethingWithAValue<T>[]): () => T[] {
// implementation
}
这应该适用于长度不超过 5 的元组,并且您可以在顶部添加其他重载以达到您在实践中需要的任何内容。它冗长且丑陋,但它应该有效。
希望对您有所帮助;祝你好运!
关于typescript - 元组的 TypeScript 中的通用类型包装,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46012987/