I do not understand why the following implementation is not accepted. I hope you can help.
type F = {
(a: number): string
(a: string, b: number): number
}
const func: F = (numberOrString: string | number, b?: number): string | number => {
if (typeof numberOrString === 'number')
return numberOrString.toString();
else if (b !== undefined)
return numberOrString.length b;
throw new Error("Can't happen");
};
The error message is:
Type '(numberOrString: string | number, b?: number | undefined) => string | number' is not assignable to type 'F'.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.ts(2322)
CodePudding user response:
It seems like it should be, right? But as it says in the function overloads section...
The implementation signature must also be compatible with the overload signatures.
(Their emphasis)
A return type of string | number
isn't compatible with a return type of string
(your first overload) or number
(your second).
In practice, this often means that your implementation signature — particularly the return type — is much broader than you would otherwise write. That's okay, because the code using the function doesn't see the implementation signature, just the overload signatures. While you can use unions for the parameter types (as you have), you can't use them for the return type because it won't be compatible.
In your example, we can solve the problem by changing the return type to any
(as you probably already know):
type F = {
(a: number): string;
(a: string, b: number): number;
};
const func: F = (numberOrString: string | number, b?: number): any => {
if (typeof numberOrString === 'number')
return numberOrString.toString();
else if (b !== undefined)
return numberOrString.length b;
throw new Error("Can't happen");
};
Normally any
is something to avoid, but in a function overload implementation signature, it's okay and sometimes necessary.