打字稿:使用函数数组输入函数,该函数返回每个函数返回类型的数组

Posted

技术标签:

【中文标题】打字稿:使用函数数组输入函数,该函数返回每个函数返回类型的数组【英文标题】:Typescript: typing a function with an array of functions that returns an array of each function return type 【发布时间】:2021-07-05 18:49:52 【问题描述】:

下面的代码可以输入正确吗?

function arrayElementTypes(...array: Array<(() => string) | (() => number) | (() => prop: string) | (() => number[])>) 
   /// .. do something
   /// .. and then return an array with each functions result
   return array.map(arg => arg())


const [varA, varB, varC] = arrayElementTypes( () => "", () => (prop: "prop"), () => [1,2,3] )
// how can this be typed appropriately so that the : 
// varA: string
// varB: prop: string
// varC: number[]

【问题讨论】:

很难知道“输入正确”是什么意思。您正在传递一组具有不同参数计数的函数,因此 array.map(arg =&gt; arg()) 对于数组联合中的最后一个函数类型无效。您也只传入 3 个函数,但正在寻找一个长度为 4 的返回数组。您是否希望将返回的数组解构为单独的类型(好像它是一个元组)或函数的返回类型的交集(好像它是一个数组)? 更正了示例。 【参考方案1】:

设法做到了

type ReturnTypes<T extends Array<(...a: any[]) => any>> = 
  [P in keyof T]: T[P] extends (...a: any[]) => infer R ? R : never


type CustomArrayElement = (() => string) | (() => number) | (() => prop: string) | (() => number[])

function arrayElementTypes<T extends CustomArrayElement[]>(...array: T): ReturnTypes<typeof array> 
   return array.map(arg => arg())


const [varA, varB, varC] = arrayElementTypes( () => "", () => (prop: "prop"), () => [1,2,3] )

谢谢大家的帮助!!

【讨论】:

【参考方案2】:

我不乐观它可以正确输入。首先,我认为您正在查看 tuple,而不是数组,因为函数的“数组”具有不同的签名,并且您希望 arrayElementTypes 的返回类型对应于返回类型“数组”中的每个函数,匹配 position-wise.

同时,我不敢说完全不可能,因为我已经看到 amazing things 可以使用泛型和条件类型的组合来完成。


编辑:我想出了一些可能有助于最终答案的“构建块”类型,但您可以看看是否可以将它们拼凑在一起:)

// any function
type Fn = () => unknown;

// a tuple/array of functions
type FnArr = readonly Fn[];

// the first function in your tuple of functions
type Head<T extends FnArr> = T extends [infer HeadFn, ...any[]] ? HeadFn : never;

// the rest of the functions in your tuple of functions
type Tail<T extends FnArr> = T extends [any, ...infer TailFns] ? TailFns : never;

使用上述构建块,您可以提取函数元组中每个函数的返回类型。这并不直接适用于解决方案,但也许一些递归定义的条件类型(泛化为任意函数元组)可以让你到达那里:)

const [varA, varB, varC] = arrayElementTypes( () => "", () => (prop: "prop"), () => [1,2,3] )
// how can this be typed appropriately so that the : 
// varA: string
// varB: prop: string
// varC: number[]

type ExampleFns = [ () => string, () => prop: "prop", () => number[] ];

type TypeForVarA = ReturnType<Head<ExampleFns>>;                // F1 = string
type TypeForVarB = ReturnType<Head<Tail<ExampleFns>>>;          // F2 = prop: "prop"
type TypeForVarC = ReturnType<Head<Tail<Tail<ExampleFns>>>>;    // F3 = number[]

【讨论】:

【参考方案3】:
const [varA, varB, varC, varD]: Array<string | number | prop: string | number[]> = arrayElementTypes( () => "", () => (prop: "prop"), () => [1,2,3] )

这是否满足您的要求?

【讨论】:

以上是关于打字稿:使用函数数组输入函数,该函数返回每个函数返回类型的数组的主要内容,如果未能解决你的问题,请参考以下文章

如何根据输入为字符串或未定义来创建返回字符串或未定义的打字稿函数?

打字稿递归函数组合

基于可选参数存在而不使用函数重载的打字稿函数返回类型

类型的打字稿传播运算符[重复]

类装饰器上的打字稿文档-返回“类扩展构造函数”的函数

打字稿通用承诺返回类型