如果TypeScript中有接口,如何在数组中指定泛型

如果TypeScript中有接口,如何在数组中指定泛型,typescript,generics,Typescript,Generics,我有一个函数,它接受一系列规范作为参数。这些规范的形状已定义,但值可以是任何形式。但是-我想提供一个泛型,让TypeScript根据传入函数的规范推断类型。下面是一个非常基本的示例: 接口规范{ 价值:你的类型; } 函数doStuff(规格:Spec[]):T[]{ 返回specs.map(spec=>spec.value); } 常量mySpecs=[ {value:1}, {value:'two'}, {value:[1,2,3]}, ]; 常量值=doStuff(mySpecs); 我

我有一个函数,它接受一系列规范作为参数。这些规范的形状已定义,但值可以是任何形式。但是-我想提供一个泛型,让TypeScript根据传入函数的规范推断类型。下面是一个非常基本的示例:

接口规范{
价值:你的类型;
}
函数doStuff(规格:Spec[]):T[]{
返回specs.map(spec=>spec.value);
}
常量mySpecs=[
{value:1},
{value:'two'},
{value:[1,2,3]},
];
常量值=doStuff(mySpecs);
我知道这里不能真正推断类型,因为它们都是不同的,但是我可以以某种方式将它们作为类型显式地添加到doStuff泛型中吗。类似于以下伪代码:

function doStuff<T>(specs: <Spec<t> for t of T>): <t for t of T> {
    return specs.map(spec => spec.value);
}

const values = doStuff<[number, string, number[]]>(mySpecs);
函数doStuff(规格:):{
返回specs.map(spec=>spec.value);
}
常量值=doStuff(mySpecs);

您必须提供
YourType
的联合类型定义,以使其正常工作:

const mySpecs = [
    {value: 1},
    {value: 'two'},
    {value: [1, 2, 3]},
];

type YourType = number | string | number[];

interface Spec<YourType> {
    value: YourType;
}

function doStuff<T>(specs: Spec<T>[]): T[] {
    return specs.map(spec => spec.value);
}

const values = doStuff<YourType>(mySpecs);
console.log(values);
const mySpecs=[
{value:1},
{value:'two'},
{value:[1,2,3]},
];
键入YourType=number | string | number[];
接口规范{
价值:你的类型;
}
函数doStuff(规格:Spec[]):T[]{
返回specs.map(spec=>spec.value);
}
常量值=doStuff(mySpecs);
console.log(值);

TypeScript 3.1引入了对使用的支持,因此如果您有一个像
[1,2,3]
这样的类型,并将一个像
{[K in keyof T]:Spec}
这样的映射类型应用到它,它将变成
[Spec,Spec,Spec]
。因此,函数的签名可以是这样的:

declare function doStuff<T extends readonly any[]>(
  specs: { [K in keyof T]: Spec<T[K]> } | []
): T;
const mySpecs = [
  { value: 1 },
  { value: 'two' },
  { value: [1, 2, 3] },
] as const;
/* const mySpecs: readonly [
  { readonly value: 1; }, { readonly value: "two"; }, { readonly value: readonly [1, 2, 3];
}] */

const moreValues = doStuff(mySpecs);
// const moreValues: readonly [1, "two", readonly [1, 2, 3]]
如果您想在使用
mySpecs
的两行中分别执行此操作,您可能应该告诉编译器不要忘记
mySpecs
是一种元组类型,如下所示:

declare function doStuff<T extends readonly any[]>(
  specs: { [K in keyof T]: Spec<T[K]> } | []
): T;
const mySpecs = [
  { value: 1 },
  { value: 'two' },
  { value: [1, 2, 3] },
] as const;
/* const mySpecs: readonly [
  { readonly value: 1; }, { readonly value: "two"; }, { readonly value: readonly [1, 2, 3];
}] */

const moreValues = doStuff(mySpecs);
// const moreValues: readonly [1, "two", readonly [1, 2, 3]]
在这里,我使用了TypeScript 3.4+来保持
mySpecs
的类型狭窄。。。可能它太窄了,因为所有内容都变成了只读。但这取决于你的工作


这将是答案的结尾,但遗憾的是,编译器无法验证
doStuff()
的实现是否符合签名:

return specs.map(spec => spec.value); // error! not callable
解决这一问题的最简单方法是首先明智地说服编译器,
specs
有一个可用的
map
方法(说它是
Spec)