When it comes to TypeScript, understanding generic conditional types can be a bit tricky. TypeScript doesn't always handle the generic conditional types smoothly, especially when it comes to looking at the Parameters<M>
utility type for generic function type M
and recognizing that the output is always spreadable. This is a known design limitation of TypeScript, as explained in microsoft/TypeScript#47615.
As per the suggested solution in that issue, the recommended approach is to make the function generic in the argument list A
and the return type R
of the function type separately. In your code, since the return type is always void
, it is sufficient to make it generic only in A
:
const factory = <A extends Parameters<typeof foo | typeof bar>>(
method: (...args: A) => void) => (...args: A) => {
method(...args);
};
By knowing that the type A
of args
is the rest parameter type for method
, the call becomes valid. Although not crucial for this example, A
has been constrained to
Parameters<typeof foo | typeof bar>
to restrict random functions from being passed in:
factory(foo)("a", "b"); // okay
factory(bar)(1, 2); // okay
factory((a: string, b: number) => { }) // error!
Here's a Playground link to code for further reference.