I have exported a function from some module that looks like:
export function MyFunc<A>() {
return {
foo: (in: A) => void
}
}
Now, in some other module, I want to be able to talk about the different return types of MyFunc
. Since I didn't export the type, I'll use typeof
to get hold of the type I want given the value MyFunc
. Ideally I would do the following:
import { MyFunc } from "mymodule";
type MyFuncReturned<A> = ReturnType<typeof MyFunc<A>>;
function foo(): MyFuncReturned<string> {
// ...
}
Hrmph, this doesn't work; typeof
can only be passed a value and doesn't like my attempt to specify the generic type of that value.
The best I can do is convincing TypeScript to infer specific types of MyFunc
from values I've created, and then giving them individual type aliases, eg:
const myFuncStringReturn = MyFunc<string>();
type MyFuncStringReturn = typeof myFuncStringReturn;
To avoid actually running MyFunc
just to get the type info, I can hide it behind a function and use ReturnType
on it:
const myFuncStringReturn = () => MyFunc<string>();
type MyFuncStringReturn = ReturnType<typeof myFuncStringReturn>;
const myFuncBoolReturn = () => MyFunc<bool>();
type MyFuncBoolReturn = ReturnType<typeof myFuncBoolReturn>;
This gives me a way of, one type at a time, talking about the different return types of MyFunc
, but it
MyFunc
in a more generic sense.The only "proper" solution I can come up with is duplicating a bunch of type info when I declare MyFunc
:
export function MyFunc<A>(): MyFuncReturns<A> {
return {
foo: (in: A) => void
}
}
export type MyFuncReturns<A> = {
foo: (in: A) => void
}
But now as I change MyFunc
, I have to make sure to keep MyFuncReturns
in sync with it.
Is there any way I can get hold of a type like MyFuncReturns<A>
given just our exported value MyFunc
, without having to add runtime code or add the boilerplate above?
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:
export function MyFunc<A>() {
return {
foo: (os : A) => {}
}
}
class Helper <T> {
Return = MyFunc<T>()
}
type FuncReturnType<T> = Helper<T>['Return']
type ForBool = FuncReturnType<boolean> // {foo: (os: boolean) => void;}
type ForString = FuncReturnType<string> // {foo: (os: string) => void;}
Note If you have constraints of A
you will need to duplicate those on T
in Helper
and FuncReturnType
, that is unavoidable unfortunately.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments