Buszmen
Buszmen

Reputation: 2426

Type based on generic (function parameter's type)

I want to have a variable type based on function parameter type. I tried to use generics, but I still have some error.

interface A {
    value: string;
}

interface B {
    value: number;
}

interface extA extends A {
    id?: string;
}

interface extB extends B {
    id?: number;
}

function foo<T extends A | B>(param: T) {
    const newParam: T extends A ? extA : extB = param;

    newParam.id = param.value;

    return newParam;
}


const a = { value: "1" } as A;
const b = { value: 1 } as B;

const resultA = foo(a); // resultA is "extA" not "extA | extB"
const resultB = foo(b); // resultB is "extB" not "extA | extB"

The code is made up, but it shows the idea. Based on the type of the function parameter param I want to use extended type of either of main types newParam. So if I choose a parameter of one of each type TS will know which type is being returned. How to achieve this?

TS Playground

Upvotes: 0

Views: 72

Answers (1)

Krzyrok
Krzyrok

Reputation: 180

If you don't need generics, then you can use function overloading in TS:

function foo(param: A): extA;
function foo(param: B): extB;
function foo(param: A | B): extA | extB {
    const newParam: extA | extB = param;
    newParam.id = param.value;

    return newParam;
}

Full playground

Type is correctly detected.

But you should watch yourself in the function implementation - you return extA | extB what can be not valid with previous overloads (developer can make mistake in implementation or add new overload and forget about implementation).
Example:

function foo(param: A): extA;
function foo(param: B): extB;
function foo(param: A | B): extA | extB {
    const newParam: extB = {
        value: 3,
        id: 22
    };

    return newParam; // always returned only `extB`
}

const a = { value: "1" } as A;
const b = { value: 1 } as B;

const resultA = foo(a);
const resultB = foo(b);

resultA.value // type detected as string
// (correct according to overloading) but implementation
// returns always number what is correct according to its definition
// but incorrect according to previous overload signatures - developer mistake

Playground

Upvotes: 1

Related Questions