Reputation: 2751
Why does this yeild an error?
type MyType = {
a: string, b: string
}
function cantInfer<In, Out>(fn: (i: In) => Out, i: In) {
}
function myFunction<K extends keyof MyType>(key: K): string {
return '';
}
cantInfer(myFunction, 'a');
But this doesn't:
type MyType = {
a: string, b: string
}
function cantInfer<In, Out>(fn: (i: In) => Out, i: In) {
}
function myFunction(key: keyof MyType): string {
return '';
}
cantInfer(myFunction, 'a');
Note, the missing <K extends keyof MyType>
in myFunction
Upvotes: 0
Views: 202
Reputation: 17417
It should be noted that your first example does type-check when strictFunctionTypes
is disabled. This disables bivariant parameter checking for function types. Without this check, the compiler allows code that may be unsound at runtime.
A good explanation can be found here:
... the question of whether a more-specific-type-accepting function should be assignable to a function accepting a less-specific type provides a prerequisite answer to whether an array of that more specific type should be assignable to an array of a less specific type. Having the latter not be the case would not be an acceptable type system in the vast majority of cases, so we have to take a correctness trade-off for the specific case of function argument types.
You fix the issue in your second example by making the type parameters for myFunction
concrete: keyof MyType
resolves to string
at compile time, meaning the type signature for myFunction
is effectively myFunction(key: string): string
The following example type-checks by doing the opposite—It makes the type constraints on canInfer
less permissive (playground link):
type MyType = {
a: string, b: string
}
function canInfer<In extends keyof MyType, Out>(fn: (i: In) => Out, i: In) {
return fn(i);
}
function myFunction<K extends keyof MyType>(key: K): string {
let myType = {
a: "foo",
b: "bar"
}
return myType[key];
}
alert(canInfer(myFunction, 'a'));
Upvotes: 2