TypeScript Version: 3.5.2
Code
function test1 (a: {
f (n: any[]): void;
}) {}
function test2 (a: {
f: (n: any[]) => void;
}) {}
test1({
f ([s]: [string]) {}
});
test2({
f ([s]: [string]) {}
});
Expected behavior:
Type check for test1 and test2 should have same result: both of them should pass type check, or neither of them pass type check
Actual behavior:
test1 passed type check, test2 didn't:
Type '([s]: [string]) => void' is not assignable to type '(n: any[]) => void'.
Types of parameters '__0' and 'n' are incompatible.
Property '0' is missing in type 'any[]' but required in type '[string]'.
I agree it's confusing but this is working as intended (as I understand it).
The type { f(n: any[]): void; } represents an object with a method named f, while the type { f: (n: any[]) => void; } represents an object with a function-valued property named f. Those are very similar, but not the same.
Specifically, with the --strictFunctionTypes compiler option enabled, parameters of functions are checked contravariantly, while parameters of methods are still checked bivariantly.
Since [string] is assignable to any[] but any[] is not assignable to [string], your test1 call passes the bivariant check but your test2 call fails the contravariant check.
--strictMethodTypes when?
When the JavaScript ecosystem isn't full of unsound class hierarchies (e.g. the DOM!)
Most helpful comment
When the JavaScript ecosystem isn't full of unsound class hierarchies (e.g. the DOM!)