What is the difference between following generic types:
type FnWithRequiredParam<T> = (t: T) => void
type FnWithParamInferred = <T>(t: T) => void
As far as I understand, the FnWithRequiredParam
will always fail if not explicitly given the generic type in any context. Passing the generic (which is enforced), e.g. FnWithRequiredParam<string>
will basically turn it into (t: string) => void
in all contexts.
However, I can't find the meaning of the FnWithParamInferred
. In some contexts <T>
gets inferred from the place it's used (such as Array.map), but the following line throws an error:
var f: FnWithParamInferred = (a: number) => { console.log(a) }
saying that number
and T
are incompatible. In above line, what is actually T
? It's never been declared precisely and is being compared to another type. What are the rules for determining what is the generic T
defined in function types like <T>(...) => ...
?
Seems that, if <T>
is defined as a required generic of a class/interface, e.g. an Array<T>
, then methods od array can successfully infer T
. But if it's outside of a class/interface, type inference doesn't seem to work.
The two are very different in the function signature they define.
T
, with T
being inferred (or specified explicitly) when the function is called.Consider the following declarations:
declare const fn: FnWithRequiredParam<number>
declare const genericFn: FnWithParamInferred;
// T was fixed on declaration
fn(1) // ok
fn("1") // err
// T is decded by the caller
genericFn(1) // ok T is number for this call
genericFn("1") // ok T is string for this call
genericFn<number>("1") // err T was specified as number but string was passed in
The reason for the error you are getting is that you are attempting to assign a function with a number
parameter to a function that should accept a parameter of any type T
, with T
to be decided by the caller of the function. Only a generic function can satisfy the type FnWithParamInferred
var f: FnWithParamInferred = <T>(a: T) => { console.log(a) }
I think what you really want is to be able to omit the explicit type argument from the variable declaration and have it be inferred based on the value assigned to it. Typescript does not support this. If you define a type annotation for a variable no inference will be done for the variable.
You can omit the type annotation altogether to let the compiler infer the function type:
var f = (a: number) => { console.log(a) } // inferred as (a: number) => void
Or you can define a generic helper function to infer T
, but restrict the function signature based on FnWithRequiredParam
function createFunction<T>(fn: FnWithRequiredParam<T>) {
return fn;
}
var f = createFunction((a: number) => { console.log(a) }) // inferred as FnWithRequiredParam<number>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With