简体   繁体   中英

Typescript: typing a function with an array of functions that returns an array of each function return type

Is it possible for the code below to be typed correctly?

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[]

Managed to do it with

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] )

Thank you all for your help!!

I'm not optimistic that it can be typed correctly. Firstly, I think you are looking at a tuple , rather than an array, since the "array" of functions have different signatures, and you want the return type of arrayElementTypes to correspond to the return type of each function in the "array", matching position-wise .

At the same time, I hesitate to say it's impossible outright, as I've seen amazing things that can be done using a combination of generics and conditional types.


Edit: I have come up with some "building-block" types that may help with the final answer, but you can see if you can piece them together:)

// 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;

Using the above building blocks, you can extract the return types of each function in your tuple of functions. This doesn't directly lend itself to a solution, but maybe some recursively defined conditional types (to generalise for arbitrary tuple of functions) can get you there:)

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[]
const [varA, varB, varC, varD]: Array<string | number | {prop: string} | number[]> = arrayElementTypes( () => "", () => ({prop: "prop"}), () => [1,2,3] )

Does this satisfy your requirements?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM