Consider the following TypeScript function:
function example<T>(
...[callback, batch]:
| [callback: (param: T) => void, batch?: false]
| [callback: (param: T[]) => void, batch: true]
) {
if (batch) {
callback([]);
} else {
callback({} as T);
}
}
The callback
type definition specifies its argument type, so one would expect the argument type to be inferred in the following calls:
example<string>((param) => {}); // Param should be inferred as string
example<string>((param) => {}, true); // Param should be inferred as string[]
However TypeScript complains it cannot infer the type of param
:
error TS7006: Parameter 'param' implicitly has an 'any' type.
example<string>((param) => {});
~~~~~
error TS7006: Parameter 'param' implicitly has an 'any' type.
example<string>((param) => {}, true);
~~~~~
Providing a explicit type does fix the problem but I believe TypeScript has enough information to infer it by itself. In fact, TypeScript does report incorrect typings when providing an invalid explicit type:
error TS2345: Argument of type '[(param: number) => void]' is not assignable to parameter of type '[callback: (c: string) => void, batch?: false | undefined] | [callback: (c: string[]) => void, batch: true]'.
Type '[(param: number) => void]' is not assignable to type '[callback: (c: string) => void, batch?: false | undefined]'.
Type at position 0 in source is not compatible with type at position 0 in target.
Type '(param: number) => void' is not assignable to type '(c: string) => void'.
Types of parameters 'param' and 'c' are incompatible.
Type 'string' is not assignable to type 'number'.
example<string>((param: number) => {});
~~~~~~~~~~~~~~~~~~~~~
error TS2345: Argument of type '[(param: number[]) => void, true]' is not assignable to parameter of type '[callback: (c: string) => void, batch?: false | undefined] | [callback: (c: string[]) => void, batch: true]'.
Type '[(param: number[]) => void, true]' is not assignable to type '[callback: (c: string[]) => void, batch: true]'.
Type at position 0 in source is not compatible with type at position 0 in target.
Type '(param: number[]) => void' is not assignable to type '(c: string[]) => void'.
Types of parameters 'param' and 'c' are incompatible.
Type 'string[]' is not assignable to type 'number[]'.
Type 'string' is not assignable to type 'number'.
example<string>((param: number[]) => {}, true);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is there any way to get this to work without the explicit argument type?