Erik Cupal
Erik Cupal

Reputation: 2935

Typescript method overloading with one parameter of different type (non-primitive)

Ok, what I would like to do is simple. I want to overload a method so that it can take one parameter, which is of non-primitive type.

I understand I can't do it like this because TypeScript losts all types when compiled to JavaScript. If one of the parameters was primitive (e.g. string), I could do it (typeof myString == "string").

public doSomething(typeA: TypeA);
public doSomething(typeB: TypeB);
public doSomething(type: TypeA | TypeB) {
    if (typeof type == "TypeA") {
        ... // obviously I can't do that, Javascript got no types
        ... // typeof type === "object"
    }
    else if (typeof type == "TypeB") { //the same }
    else { //undefined }
}

What I thought up is this:

public doSomething(typeA?: TypeA, typeB?: TypeB) {
    if (typeA) { ... }
    else if (typeB) { ... }
    else { //undefined }
}

Then I have to call this way:

doSomething(typeA, undefined); //to call TypeA version
doSomething(undefined, typeB); //to call TypeB version

Is such a design acceptable or is it better to rather create two separate methods?

EDIT:

This notation is probably better. You are forced (by IDE) to add the undefined when you're calling the method.

public doSomething(typeA: TypeA | undefined, typeB: TypeB | undefined) {
    if (typeA) { ... }
    else if (typeB) { ... }
    else { //undefined }
}

Upvotes: 0

Views: 928

Answers (1)

Nitzan Tomer
Nitzan Tomer

Reputation: 164237

You can have functions that check whether a value is of a certain type, and typescript has the notion of user defined type guards:

interface TypeA {
    x: string;
}
function isTypeA(value: any): value is TypeA {
    return Object.keys(value).length === 1 && typeof value.x === "string";
}

interface TypeB {
    y: number;
}
function isTypeB(value: any): value is TypeB {
    return Object.keys(value).length === 1 && typeof value.y === "number";
}

function doSomething(typeA: TypeA);
function doSomething(typeB: TypeB);
function doSomething(type: TypeA | TypeB) {
    if (isTypeA(type)) {
        console.log(type.x);
    } else {
        console.log(type.y);
    }
}

(code in playground)

In your example, as the passed value can be only of TypeA and TypeB then there's no need for the extra if/else.
But you can also use the isTypeB.

This method is good if you need this check in a few places in your code, but if you need it for just that one function, then I think that I would go with two different functions, depending on the amount of duplicated code.

Upvotes: 1

Related Questions