In my experience, I have noticed a discrepancy in TypeScript's type inference when dealing with conditional return statements in functions. I have two identical functions, register and register2, outlined below:
const register = (step: 1 | 2) => {
if (step === 1) {
return {
otp: "",
};
}
return {
userId: "",
};
};
const register2 = (step: 1 | 2) => {
if (step === 1) {
const res = {
otp: "",
};
return res;
}
const res = {
userId: "",
};
return res;
};
Both functions yield objects with the same format based on the value of the step parameter. However, TypeScript interprets these two functions as having different return types.
register
generates a union type:
{ otp: string; userId?: undefined; } | { userId: string; otp?: undefined; }
register2
leads to a union type:
{ otp: string; } | { userId: string; }
Scenario
const user = register(1);
if (user.otp) {
// **
} else {
// **
}
This scenario works flawlessly
const user2 = register2(1);
if (user2.otp) {
// **
} else {
// **
}
In this case, accessing user2.otp
results in an error:
Property 'otp' does not exist on type '{ otp: string; } | { userId: string; }'
Of course, one way to resolve this issue is by using "otp" in user2
, but this solution lacks type safety compared to the first case because "otp" could be renamed or may never appear in the response
My goal is to Ensure that register2 returns the same type as the output of register without explicitly defining it