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