lapuckire lapuckire - 1 month ago 6
TypeScript Question

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

Answer

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.