Understanding where generic type parameters are declared and their scope is crucial. The definition
type FuncGenericReturn = <T>() => T;
represents a concrete type for a generic function. In <T>() => T
, it indicates: "a function where the caller specifies a type T
and receives a value of type T
." However, actual implementation is practically impossible. Consider if such a function existed:
declare const funcGenericReturn: FuncGenericReturn;
This would imply calling it like this:
const someNumber: number = funcGenericReturn<number>();
const someString: string = funcGenericReturn<string>();
Though at runtime, both calls would compile to:
const someNumber = funcGenericReturn();
const someString = funcGenericReturn();
Thus, funcGenericReturn()
would need to somehow determine at runtime whether to return a number
or a string
, relying on type information that gets erased before producing JavaScript. Hence, truly implementing a FuncGenericReturn
demands precognitive abilities.
To reiterate: when dealing with a generic function, the generic type parameters are dictated by the caller, not the implementer. While the compiler may sometimes infer these type parameters to ease coding burden, such inferences occur at call time. Subsequently, two distinct calls to the same generic function could lead to different type parameter selections.
Contrast this scenario with a related but different type declaration:
type FuncConcreteReturn<T> = () => T;
In this case, FuncConcreteReturn
denotes a generic type relating to a specific function. It's more accurate to view FuncConcreteReturn
as a type operator that accepts an input type T
and outputs the type () => T
.
For any given type T
, the type FuncConcreteReturn<T>
represents a concrete function type devoid of parameters and yielding a value of type T
. Thus FuncConcreteReturn<string>
signifies a function returning a string without arguments, while FuncConcreteReturn<number>
implies a number-returning function sans parameters. Note the distinction between FuncConcreteReturn<string>
and
FuncContreteReturn<number></code, neither of which represent a standard <code>FuncConcreteReturn
due to invalid syntax. Consequently, the following usage is valid:
const funcReturnsNumber: FuncConcreteReturn<number> = () => 1;
const funcReturnsString: FuncConcreteReturn<string> = () => "";
Thus, funcReturnsNumber
isn't merely a generic function; rather, it's a fixed-function always outputting a number. Additionally, FuncConcreteReturn<T>
functions as a generic type, with the designation of its T
value occurring during its definition. As these types pertain to function types, the decision on T
rests with the developer creating these functions, not the caller.
Lastly, consider the relationship between a generic function type such as
type G = <T, U>(t: T, u: U) => [T, U]
and a generic type like
type H<T, U> = (t: T, u: U) => [T, U]
An instance of the former correlates with an instance of the latter, though not vice versa. This means having a FuncGenericReturn
allows assignment to either a FuncConcreteReturn<string>
or a FuncConcreteReturn<number>
:
const fn: FuncConcreteReturn<number> = funcGenericReturn; // acceptable
const fs: FuncConcreteReturn<string> = funcGenericReturn; // proven
Similarly, for types G
and
H</code:</p>
<pre><code>const g: G = <T, U>(t: T, u: U) => [t, u];
g("a", 1); // valid
g(1, "a"); // permitted
const h1: H<string, number> = g; // okay
h1("a", 1); // accepted
h1(1, "a"); // rejected
const h2: H<number, string> = g; // verified
h2(1, "a"); // granted
h2("a", 1); // denied
Understood now? Hopefully, you've grasped the distinction between generic functions and generic types. Best of luck!
Code Playground Link