TypeScript: Is it possible to get the return type of a generic function?
It’s a long time but TypeScript finally supported it. Since v4.7 (still in beta as of this writing), with the help of Instantiation Expressions feature we can now do this:
I created this playground so people can play with it. See here and here for more information.
Titian’s solution above works great if the Generic is only applied inside the function body.
However, there are cases that the Generic Type is a part of the arguments and/or return type. e.g.
function MyFunc3(r: number, p: T, x: boolean): T
So, to generalize Titian’s solution and support fixating both the arguments and the return type of any generic function, I wrote the following:
Required Utility Types
// From https://stackoverflow.com/a/53808212 by jcalz (https://stackoverflow.com/users/2887218) export type IfEquals = (() => G extends T ? 1 : 2) extends (() => G extends U ? 1 : 2) ? Y : N; // Aidin: Please comment if you could make the following shorter! type ReplaceType = IfEquals; type ReplaceTypeInArray = ARR extends [] ? [] : ARR extends [infer P0] ? [P0 extends F ? T : P0] : ARR extends [infer P0, infer P1] ? [ReplaceType, ReplaceType] : ARR extends [infer P0, infer P1, infer P2] ? [ReplaceType, ReplaceType, ReplaceType] : ARR extends [infer P0, infer P1, infer P2, infer P3] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType] : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType] : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType] : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5, infer P6] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType] : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5, infer P6, infer P7] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType] : ARR extends [infer P0, infer P1, infer P2, infer P3, infer P4, infer P5, infer P6, infer P7, infer P8] ? [ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType, ReplaceType] : never;
Sample Functions
type ALL = string | number | object | boolean; export function MyFunc1() < return < foo: (os : T) =><> > > function MyFunc2(r: 55, p: T, x: boolean): T
Fixation examples
// Inspired by https://stackoverflow.com/a/52964723 by Titian (https://stackoverflow.com/users/125734) class Helper1 < Fixate = (. args: ReplaceTypeInArray, ALL, T>) => MyFunc1(. args); > type FixatedFunc1 = Helper1['Fixate']; // -- Usage type ForNumber1 = FixatedFunc1 // void;> type ForString1 = FixatedFunc1 // void;> // ~~~~~~~~~~~~~~~~~~~ class Helper2 < Fixate = (. args: ReplaceTypeInArray, ALL, T>) => MyFunc2(. args); > type FixatedFunc2 = Helper2['Fixate']; // -- Usage type ForNumber2 = FixatedFunc2 // (args_0: 55, args_1: number, args_2: boolean) => number type ForString2 = FixatedFunc2 // (args_0: 55, args_1: string, args_2: boolean) => string
Playground Link (Contains all 3 parts)
Now, one can simply use ReturnType or Parameteres on any of these fixated function types!
There is a proposal to allow using typeof with arbitrary expressions to allow things like getting the return type of a generic functions for a specific type argument (see here and here)
A more generic workaround that works today is to use a generic class with a field that is tied to the return type of the function. We can then extract the field of the class. Since for classes we can specify generic type parameters in type expressions we can extract the generic form of the return type:
Note If you have constraints of A you will need to duplicate those on T in Helper and FuncReturnType , that is unavoidable unfortunately.
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use typeof with generic #20719
Use typeof with generic #20719
Comments
TypeScript Version: Current playground version (?)
class GenericGroupT> items: ArrayT> = []; constructor(name: string) > > type CheckboxValues = string; type CheckboxesGroup = new (name: string) => GenericGroupCheckboxValues>; const Checkboxes: CheckboxesGroup = GenericGroup; const checkboxes = new Checkboxes('checkboxes'); checkboxes.items.map(item => item.toUpperCase()); type RadioValues = string; type RadiosGroup = typeof GenericGroup RadioValues>; const Radios: RadiosGroup = GenericGroup; const radios = new Radios('radios'); radios.items.map(item => item.toUpperCase());
Expected behavior:
typeof GenericGroup; is equivalent to new (name: string) => GenericGroup;
Actual behavior:
Syntax error, because typeof GenericGroup; is not supported.
In my use case I have a class with a generic (like GenericGroup ) which extends a class from a 3rd party lib. The class from the 3rd party lib uses multiple params in its constructor. When I alias my class with the filled generic I don’t want to write the parameters for the 3rd party lib every time (as done with new (name: string) => GenericGroup; ) as I don’t really maintain them.
(There seem to be multiple related issues, but I couldn’t found an issue with exactly this problem.)
The text was updated successfully, but these errors were encountered: