TypeScript Version: 3.4.3
Search Terms:
union mutual exclusion
Code
type A = { A: string };
type B = { B: string };
let ab: A | B = {
A: 'xxxxxxxxx',
B: 123
}
Expected behavior:
Compiled error.
ab should be a mutual exclusion between A and B.
A or B, shouldn't have 2 fields at the same time.B is wrongActual behavior:
Compiled succ.
Playground Link:
Related Issues:
I'd expect a EPC error (excess property checks) as well. But besides that your object literal fulfills the contract of type A and of type B, so the assignment is valid.
Playground link: https://typescript-play.js.org/#code/...
Related Issues: #12936 and https://github.com/Microsoft/TypeScript/issues/12936#issuecomment-284590083 and #14094.
The issue tracking this particular problem is #20863 --- there is no discriminant property for the union type.
Union types are not intended to be automatically mutually exclusive
@RyanCavanaugh ab.B === 123 is also working as intended?
Neither type A nor type B define property B could be a number
For an assignment S to T | U, the assignment is valid if S is a valid assignment to either type. { A: string, B: number } is a valid { A: string }, therefore the assignment is valid.
@RyanCavanaugh
{ B: number } never defined in A and B.
So can I understand this as:
S is valid to A or BS is valid to A|B, But why {A: 'XXXXX', C: 12345} is not valid?
The things that excess property checking warns about aren't things related to subtyping or assignability.
@RyanCavanaugh is it intended for VSCode intellisense to provide auto completion for B if A is already declared in an object literal?
I would guess not, but I stumbled across this today:

In my understanding the intent is pretty clear that bar is either supposed to be called with {a: string} or {b: number}, not both. While it is legal to do so, I would expect intellisense to not propose b as an auto completion entry here.
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
@RyanCavanaugh it doesn't make any sense, code above, because it doesn't fulfill A, neither does it fulfill B, it only fulfill A & B, union isn't exclusively but it should fulfill at least one of them, in this case it doesn't fulfill anyone of them.
type A = { a: string };
type B = { b: string };
type T = A | B;
// error: Object literal may only specify known properties
const a: A = {
a: 'xxxxxxxxx',
b: 'yyyy'
};
// error: Object literal may only specify known properties
const b: B = {
a: 'xxxxxxxxx',
b: 'yyyy'
};
// what?
const t: T = {
a: 'xxxxxxxxx',
b: 'yyyy'
};
Most helpful comment
I'd expect a EPC error (excess property checks) as well. But besides that your object literal fulfills the contract of type
Aand of typeB, so the assignment is valid.Playground link: https://typescript-play.js.org/#code/...
Related Issues: #12936 and https://github.com/Microsoft/TypeScript/issues/12936#issuecomment-284590083 and #14094.