I've been trying but failing to get this union type to work as I want, is this just not supported?
type TestA = { href: string; a: string };
type TestB = { href?: never; b: string };
type TestUnion = TestA | TestB;
const test = (x: TestUnion) => {
if (x.href) {
console.log("X is TestA", x.a);
} else {
console.log("x should be TestB, but is TestUnion", x.b); // error
}
};
CodePudding user response:
In
const testBad = (x: TestUnion) => {
if (x.href) {
console.log("X is TestA", x.a.toUpperCase());
} else {
console.log("x should be TestB, but is TestUnion",
x.b.toUpperCase());
//~ <-- error, property b does not exist on TestA
}
};
the type of x.href starts off as string | undefined. Using (x.href) as a condition in an if statement is performing a truthiness check. And while a truthy x.href implies that x.href can be narrowed to string, a falsy x.href does not imply that x.href can be narrowed to undefined, because the empty string "" is falsy.
Thus you can get into the else block with a TestA unintentionally like this:
testBad({ href: "", a: "" }); // compiles, but
// RUNTIME ERROR 