Typescript overload functions don't autocomplete correctly in IDE

Viewed 174

I've been trying to make function overloads so my IDE could autocomplete the second paramater's type correctly based on the first argument's value. See example below:

class Animal {
    constructor(private name: string) { }

    bark(key: 'said', data: {
        text: string;
    }): void;
    bark(key: 'barked', data: {
        times: number;
    }): void;
    bark(key: 'said' | 'barked', data: any): void {
        if (key === 'said') console.log(`${this.name} said ${data}`);
        if (key === 'barked') for (let i = 0; i < data; i++) console.log('BARK!');
    }
}

const barry = new Animal('Barry');
barry.bark('barked', {
    /* Should auto-complete to { times: number } */
})

However the IDE autocompletes to both types for 'barked' and 'said'. See following example executed on Typescript sandbox

Code

Am I typing it incorrectly? Or perhaps expecting something that is not supported? Thanks!

1 Answers

Great question. it seems Typescript is unable to infer the narrowest type (from the first parameter) when working with overloads.

One way to achieve what you want is by using Generics. here is how it can be done in your case:

type Type1 = {text: string}
type Type2 = {times: number}

class Animal {
    constructor(private name: string) { }

    bark<Key extends "said" | "barked", Data extends (Key extends "said" ? Type1 : Type2)>
    (key: Key, data: Data) : void;
    bark(key: any, data: any): any {
        if (key === 'said') console.log(`${this.name} said ${data}`);
        if (key === 'barked') for (let i = 0; i < data; i++) console.log('BARK!');
    }
} 

    
 const barry = new Animal('Barry');
 barry.bark("barked", {times: 5})

Although this works fine in your case, but it's not quite straightforward.

Related