How can I get the type of a generic function applied to a parameter in TypeScript?
For example, how could I define Apply
below?
declare function f<T>(t: T): T extends number ? boolean : object;
type ResForNumArg = Apply<typeof f, number>; // should be boolean
type ResForStringArg = Apply<typeof f, object>; // should be object
If there's no way to do this, one can hack around the problem for specific cases by making a type alias that is a type-level version of the function, like F
below:
declare function f<T>(t: T): T extends number ? boolean : object;
type ApplyF<T> = T extends number ? boolean : object;
type ResForNumArg = ApplyF<number>; // boolean
type ResForStringArg = ApplyF<object>; // object
But ApplyF
can fall out of sync with f
and is annoying to type. Is there a better way?
Update: this seems to be related to https://github.com/microsoft/TypeScript/issues/29043
As you correctly have found it is not possible to use function declaration as generic type, its not possible to apply the generic without function execution. We can only apply generic during calling of the function (or will be infered from the argument):
const r1 = f<number>(1) // boolean
const r2 = f(1) // boolean
Ok so we understand it is not possible. Now the workaround, in order to have it working without loosing connection with original declaration I propose additional generic type FType
. Consider:
type FType<T> = (t: T) => T extends number ? boolean : object;
// join function declaration with FType:
declare function f<T>(...t: Parameters<FType<T>>): ReturnType<FType<T>>
type ResForNumArg = ReturnType<FType<number>>; // bool
type ResForStringArg = ReturnType<FType<object>>; // object
By using utility types Parameters
and ReturnType
I connected FType
with function f
declaration. Its verbose but we get what we want finally and FType
can be applied in the standard way.