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