It's useful to allow consumers to provide configuration either as static data, or as a function returning that same schema of data.
Consider some example types:
type T1 = { a: string } | (() => { a: string });
type T2 = { b: boolean, c: number } | (() => { b: boolean, c: number });
type T3 = string[] | (() => string[]);
In general, these types look like:
type T<V> = V | (() => V);
How can I write a type which takes some value in the form of T<V>
, and returns V
?
I tried:
type ResolveMaybeFunction<T> = ReturnType<T> | T;
But this is no good because ReturnType<T>
results in any
, so ResolveMaybeFunction<T>
always results in any
.
Overall, I want the following results:
ResolveMaybeFunction<string | (() => string)> === string;
ResolveMaybeFunction<{ a: number[] } | (() => { a: number[] })> === { a: number[] };
ResolveMaybeFunction<AnyArbitraryType | (() => AnyArbitraryType)> === AnyArbitraryType;
You need to use a Conditional Type to check if the given type is a function, and then use the return type of the function if it is.
type ResolveMaybeFunction<T> = T extends ((...args: any) => any) ? ReturnType<T> : T
This says if T
is of type function with any number of arguments and has a return value, use the return type of the function.
Otherwise, just use the original type