Home > OS >  generic type for ...args?
generic type for ...args?

Time:05-28

I have a function time

const time = <T>(fn: (...args: any[]) => Promise<T>, ...args: any[]): Promise<T> => {
  return new Promise(async (resolve, reject) => {
    const timer = setTimeout(() => reject(`Error: ${fn.name} timed out`), ms)
    try {
      resolve(await fn.bind(thisArg)(...args))
    } catch(err) {
      reject(err)
    } finally {
      clearTimeout(timer)
    }
  })
}

I am wondering if there is a way to avoid using any as the type of ...args? Specifically because I want to relate the type of ...args in the fn signature (fn: (...args: any[]) => Promise<T>) with the type of ...args (the second parameter of the time function). These two ...args are the same args, so it seems like they should be related by a generic. I thought of something like this:

const time = <T, U>(fn: (...args: U[]) => Promise<T>, ...args: U[]): Promise<T>

but that seems wrong because the arguments will not all be of the same type. Rather, whatever the type is of ...args in the fn signature, will also be the type of the second parameter ...args of the time function.

CodePudding user response:

We can do something like:

const time = <T, U extends unknown[]>(fn: (...args: U) => Promise<T>, ...args: U): Promise<T>

Playground Link

the arguments will not all be of the same type

The type of ...args must indeed be an array/tuple, because it uses a rest operator.

But instead of typing as U[], which indeed forces each individual argument to be of type U, we can simply type the whole array with a generic, provided that it is constrained to be an array: U extends unknown[] and now we can do ...args: U

  • Related