skip to Main Content

I’m trying to write typing for a function I’m writing.
I made it more simple to understand using this straightforward code example:

const getValues: <T extends Array<() => any>>(
  ...args: T
) => T extends Array<() => infer R> ? R[] : null = (...args) =>
  args.map((arg) => arg());

const values = getValues(
  () => "a",
  () => 123
);

I want values to be of type [string, number] but instead it’s of type (string|number)[]

2

Answers


  1. Chosen as BEST ANSWER

    Found it!

    const getValues: <T extends readonly unknown[] | []>(
      ...args: T
    ) => { -readonly [P in keyof T]: ReturnType<T[P]> } = (...args) =>
      args.map((arg) => arg());
    
    const values = getValues(
      () => "a",
      () => 123
    );
    

  2. To ensure that the values array is inferred as [string, number] instead of (string|number)[], you can update the typing of your getValues function. Here’s an adjusted version of your code:

    const getValues: <T extends Array<() => any>>(
      ...args: T
    ) => T extends Array<() => infer R> ? { [K in keyof T]: R } : null = (...args) =>
      args.map((arg) => arg()) as any;
    
    const values = getValues(
      () => "a",
      () => 123
    );
    

    By using a mapped type { [K in keyof T]: R }, we ensure that the resulting type of getValues is an array with the same length as the input array, where each element has the inferred type R. In this case, R will be inferred as string for the first function and number for the second function, resulting in the desired type [string, number] for the values variable.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search