Search code examples
typescriptvisual-studio-codeoverloadingintellisensesignature

TypeScript: Overloaded functions/methods with object argument and IntelliSense


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?

Example for IntelliSense not working correctly


Solution

  • Both your issues depend on the fact that union types in Typescript are not exclusive. You can find several discussions on this topic:

    XOR in union allows both

    Proposal: Add an "exclusive or" (^) operator

    While this behaviour might seem confusing (it still is for me, to some extent) it explains:

    1. 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

    2. 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}