键入工厂功能

时间:2019-02-18 07:43:48

标签: typescript typescript-generics

我有一个运行时构造的函数列表,这些函数用一个参数初始化,并返回不同的内容:

 mythings: [
   param => ({foo: param, bar: 2}),
   param => ({baz: param, qux: 4}),
 ]

现在,我想编写一个工厂函数来创建这些东西的子集,例如:

const createThings = (things) => things.map(thing => thing("param"));

我正在努力键入工厂功能。我最近的尝试如下:

// MyCreator?

const createThings = <T>(things: MyCreator<T>[]) =>
  things.map(thing => thing("param"));

但是这种尝试不起作用。有想法吗?

1 个答案:

答案 0 :(得分:3)

您可以使用映射的数组/元组从数组中的每个项目中提取返回类型:

const mythings = [
   (param: string) => ({foo: param, bar: 2}),
   (param: string) => ({baz: param, qux: 4}),
 ]
type AllReturnTypes<T extends Array<(...a: any[])=> any>> = { 
    [P in keyof T]: T[P] extends (...a: any[])=> infer R?R:never
}

const createThings = <T extends Array<(...a: any[])=> any>>(things: T): AllReturnTypes<T> =>
  things.map(thing => thing("param") )as any; // assertion necessary unfortunately 

createThings(mythings) // ({ foo: string; bar: number; } | { baz: string; qux: number; })[]

您还可以将myThings设置为元组类型,以便为结果中的每个索引获得更多的精确类型:

function tuple<T extends any[]>(...a: T) {
    return a;
}
const mythings = tuple(
    (param: string) => ({ foo: param, bar: 2 }),
    (param: string) => ({ baz: param, qux: 4 }),
)

let r = createThings(mythings) // [{ foo: string; bar: number; }, { baz: string; qux: number; }

或者在打字稿3.4中,您可以使用as const

const mythings = [
    (param: string) => ({ foo: param, bar: 2 }),
    (param: string) => ({ baz: param, qux: 4 }),
] as const