On this scenario:
type Type = {
a: string;
b: string;
} | {
a: number;
b: number;
};
const func = ({a, b}: Type): string => {
if (typeof a === 'string') {
return b;
}
return 'w/e';
}
func({a: 1, b: 'w/e'});
I get an error on return b; stating
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
From what I understand by the error, Typescript interprets the Type type as
type Type = {
a: string | number;
b: string | number;
};
, but even if that is the case, why can't I call the func function with a string and a number?
The error on the call states
Argument of type '{ a: number; b: string; }' is not assignable to parameter of type 'Type'.
Type '{ a: number; b: string; }' is not assignable to type '{ a: number; b: number; }'.
Types of property 'b' are incompatible.
Type 'string' is not assignable to type 'number'.
(ts version: 4.7.2)
Playground link
The function call with the wrong types was just to test my hypothesis on why I get the previous error. Why do I get an error at return b; is what I don't understand.
Ok, the answer is Discriminated Unions.
I have to use a discriminant, a common property in each element of the union.
That, discriminant, property:
isPrimary: true, not isPrimary: boolean.Then I can check for that property's value to assume the other properties' types.
Also, in Typescript versions < 4.6, If i have an object with a type specified as above, If i destructure it, then the new variables are considered independent and I will continue getting an error similar to the initial example. Destructuring works in version 4.6 or higher.
Playground example (version 4.6)
Playground example (version 4.5)
Helpful links:
Thank you @Austaras and @coglialoro
TS cannot track the relationship of a and b after you destruct them, so they both be inferred string | number. TS 4.6 introduced a limited control flow analysis for destructing, which only applies to discriminated union.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With