I tried to overload a function f
like this (just an example of course):
function f(params: {x: number, y: number}): number;
function f(params: {x: number, z: number}): number;
function f(params: {x: number, y: number} | {x: number, z: number}): number {
if ('y' in params) return params.x + params.y;
if ('z' in params) return params.x * params.z;
}
This already causes a problem because the compiler gives me “Function lacks ending return statement and return type does not include 'undefined'.ts(2366)”
. This is strange, as one of the two if
conditions in the implementation always must be fulfilled.
But I'm here for something different (which, however, is probably related): When I want to call f
and therefore write something like f({y: 4,
and then press Ctrl+Shift+Space to activate IntelliSense (in VSCode 1.58.2), it makes two suggestions for missing properties (see picture): x
, which is correct, but also z
, which cannot fit anymore.
I would expect that as soon as I enter y
, the type of params
is narrowed to {x: number, y: number}
, but this does not seem to happen. Why is that and can I do anything to change it?
Both your issues depend on the fact that union types in Typescript are not exclusive. You can find several discussions on this topic:
Proposal: Add an "exclusive or" (^) operator
While this behaviour might seem confusing (it still is for me, to some extent) it explains:
why your two if
conditions are not considered exhaustive by the Typescript compiler: in fact you still could have the case where params
has both x
and z
why Intellisense is showing x
, y
, and z
as possible properties of params
: in fact this is considered a valid assignment by TS:
const a: { x: number, y: number } | { x: number, z: number } = { x: 1, y: 2, z: 3}