Reputation:
I have a function that has some overloads.
function foo(x: number, y: void): void;
function foo(x: number, y: number | string): number;
function foo(x: number, y: any) {
if (typeof y === "undefined") {
return;
}
return typeof y === "string"
? x / parseFloat(y)
: x / y;
}
Instead of using the optional argument for y
, I specifically use void
to specify the return value. The intended use cases include one where it is called with undefined
as the second argument.
In another function, I will call it like so:
function bar(x: number, y?: number | string) {
const f = foo(x, y);
// Some other stuff
}
This causes the following type error:
Argument of type 'string | number | undefined' is not assignable to parameter of type 'string | number'.
Type 'undefined' is not assignable to type 'string | number'.
My understanding was that foo
would take as the second argument a string | number | void
, and that when bar
invokes it, it would be passed either string
, number
, or void
, and TypeScript would be clear about the foo
's return value.
What is the correct way of achieving the intended effect?
Upvotes: 2
Views: 1685
Reputation: 40614
There is no way for the compiler to know whether y
inside bar
will be of type number | string
or undefined
since both are possible. If the compiler is not able to figure this out there is no way it can pick the correct overload. You have to provide more help to the compiler:
Assert that y
can never be undefined
:
function bar(x: number, y?: number | string) {
// Picks `function foo(x: number, y: number | string): number;` overload
const f = foo(x, y!); // Use the non-null assertion operator here.
// Some other stuff
}
Or use type guards:
function bar(x: number, y?: number | string) {
if (y === undefined) {
// Picks `function foo(x: number, y: void): void;` overload
foo(x, y);
}
else {
// Picks `function foo(x: number, y: number | string): number;` overload
const a = foo(x, y);
}
// Some other stuff
}
Upvotes: 1