Say I have a type definition for a "Middleman" function like this:
type Middleman = (
callback: () => any
) => any
This function does "some task", then calls "callback" and returns its value. Right now both Middleman and the callback are typed to return any, but I would like to strongly type this.
I have tried introducing a type parameter like so:
type Middleman<T> = (
callback: () => T
) => T
But this causes issue when trying to create an implementation of this function:
const middlemanImpl: Middleman<T> = cb => cb(); // Error, no way to get T here
As Middleman expects a "T" and can't seem to infer it from each call site.
Is there a way to achieve what I am trying to accomplish here? That is: a type definition for a generic function that returns the type of the return value of a function passed as an argument?
CodePudding user response:
You don't want Middleman
to really be a generic type that refers to a specific function:
type BadMiddleman<T> = (callback: () => T) => T;
In this version, you cannot mention the type BadMiddleman
without specifying the type parameter T
. And once you do that, any call to the function has to use that specified type T
:
const numMiddleman: BadMiddleman<number> = cb => cb();
numMiddleman(() => 12); // okay
numMiddleman(() => "abc"); // error
Instead, you want Middleman
to be a specific type that refers to a generic function. The difference is in the scope of the generic type parameter:
type Middleman = <T>(callback: () => T) => T;
const middlemanImpl: Middleman = cb => cb(); // okay
Now it is the call to a function of type Middleman
which decides what type T
is:
const num = middlemanImpl(() => 12); // okay
num.toFixed();
const str = middlemanImpl(() => "abc"); // okay
str.toUpperCase();