Reputation: 2426
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?
Upvotes: 0
Views: 72
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;
}
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
Upvotes: 1