Hey you! Do you want to get the return type of a function and use it, without knowing what it really is, or asking the user of your thing to supply it outright?
Of course you do.
type GetReturnType<original extends Function> =
original extends (...x: any[]) => infer returnType ? returnType : never
Conditional types in typescript allow you to introduce type variables into the expression in a rather dynamic way. Notice the infer
keyword. That says to TypeScript: "I want to take whatever TypeScript infers to be at this position and assign it to the name returnType
". It just so happens that the thing at that position is the return type of a given function, that we have called original
.
What happens when you put it into action? I AM SO GLAD YOU ASKED! Take this extremely powerful, useful, and all-round fantasmical Higher Order Function
const someRandomStuff = <fn extends Function>(originalFn: fn) => {
const result: GetReturnType<fn> = originalFn(12345);
return result;
}
The type of result
is going to be whatever the return type of originalFn(12345)
is. We don't actually know, until...
const innerFn = (item: number) => item.toString();
FYI, TS will infer the output of innerFn
to be a string. Then...
const output = someRandomStuff(innerFn); // ALL SYSTEMS GO
Would you like to play a game? What is the type of output
? The answer is: What is the type of innerFn
?
It's a string!
If it weren't for this trick, the type of output
would be any
. I know, I was surprised too. But it's true.
You can do the same sort of thing with anything that TypeScript can infer. Wanna get the type of arguments?
type NYET = never // preparation for unfunny joke
type GetArgumentType<original extends Function> =
original extends (...x: infer argumentsType) => any ? argumentsType : NYET
That's all, see you next time.
Top comments (1)
I guess it's worth mentioning there is built in type
ReturnType<fn>
which can be used to infer the return type of any given function.