Typescript overloads using an argument value to define the type of another parameter

Viewed 215

I have this piece of code (simplified example):

Typescript playground

It's basically an overloaded function that might get 3 different types of object, and will call a different function to each type. I'm differentiating the calls by passing a type parameter that should define the obj type and the return type.

type OBJECT_A = "OBJECT_A";
type OBJECT_B = "OBJECT_B";
type OBJECT_C = "OBJECT_C";

type OBJ_IN = OBJECT_A | OBJECT_B | OBJECT_C
type TYPES_IN = "OBJECT_A" | "OBJECT_B" | "OBJECT_C"
type OBJ_OUT = OBJECT_A | OBJECT_B | OBJECT_C

function someFunction(obj: OBJECT_A, type: "OBJECT_A"): OBJECT_A
function someFunction(obj: OBJECT_B, type: "OBJECT_B"): OBJECT_B
function someFunction(obj: OBJECT_C, type: "OBJECT_C"): OBJECT_C
function someFunction(obj: OBJ_IN, type: TYPES_IN): OBJ_OUT {
    if (type === "OBJECT_A") {
        return GET_OBJECT_A(obj as OBJECT_A);   // <<<<< TYPE ASSERTION HERE
    }
    else if (type === "OBJECT_B") {
        return GET_OBJECT_B(obj as OBJECT_B);   // <<<<< TYPE ASSERTION HERE
    }
    else {
        return GET_OBJECT_C(obj as OBJECT_C);   // <<<<< TYPE ASSERTION HERE
    }
}


function GET_OBJECT_A(obj: OBJECT_A): OBJECT_A {
    return obj
}

function GET_OBJECT_B(obj: OBJECT_B): OBJECT_B {
    return obj
}

function GET_OBJECT_C(obj: OBJECT_C): OBJECT_C {
    return obj
}

Note: In this example I've simplified the return type to be as the same type of the obj. In my real case the return type is kind of a Partial<OBJECT> for each case.

QUESTION

My question is why is Typescript demanding those type assertions? If I'm already checking type === "OBJECT_A, isn't it already clear (from the overload signatures) that obj must be of type OBJECT_A?

Is there a better pattern to handle this? Or should I just stick with the type assertions?

Without the type assertions, Typescript will complain about the calls:

enter image description here

UPDATE:

The idea for the type parameter was to avoid creating functions to check if the obj was type A | B | C, like function IS_OBJECT_A(obj) : obj is OBJECT_A, etc. I would have to check for properties, or something like that. The idea is that when I pass type: "OBJECT_A" the only overload call that allows it should make sure that obj is of course obj: OBJECT_A.

0 Answers
Related