When calling a function with an argument, the argument type is assigned to the parameter type. In other words, the argument type must be equal to, or narrower than, the parameter type.
Example:
const foo = (bar: string | number) => {
console.log(bar);
}
foo('bar');
The above works fine because 'bar'
(a string literal type) is assignable to string | number
.
Now, consider a callback scenario instead:
const foo = (bar: (baz: string | number) => void) => {
bar('baz');
// We should probably also have a call with a numeric parameter here, like bar(42),
// since the callback signature implies that it is also called that way.
}
const bar = (baz: string) => {}
foo(bar);
We get this error message on bar('baz')
:
Argument of type '(baz: string) => void' is not assignable to parameter of type '(baz: string | number) => void'.
Types of parameters 'baz' and 'baz' are incompatible.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.ts(2345)
As seen, in the callback case, TS attempts to assign type (baz: string) => void
(the argument type) to (baz: string | number) => void
(the parameter type). That was as expected.
The parameter of the callback, however, is assigned in the opposite direction: Type string | number
(parameter of callback argument) is assigned to type string
(parameter of callback parameter).
How come the assignment direction of the parameters in the callback are inverted from the non-callback scenario?