According to the blog post introducing union excess property checking in TypeScript 3.5, TypeScript will check that it belongs to at least one type:
In TypeScript 3.4 and earlier, certain excess properties were allowed in situations where they really shouldn’t have been. For instance, TypeScript 3.4 permitted the incorrect name property in the object literal even though its types don’t match between Point and Label.
type Point = {
x: number;
y: number;
};
type Label = {
name: string;
};
const thing: Point | Label = {
x: 0,
y: 0,
name: true // uh-oh!
};
Previously, a non-disciminated union wouldn’t have any excess property checking done on its members, and as a result, the incorrectly typed name property slipped by.
In TypeScript 3.5, the type-checker at least verifies that all the provided properties belong to some union member and have the appropriate type, meaning that the sample above correctly issues an error.
The blog post goes on to explicitly describe overlap as being valid:
Note that partial overlap is still permitted as long as the property types are valid.
const pl: Point | Label = {
x: 0,
y: 0,
name: "origin" // okay
};
Based on the phrase "all the provided properties belong to some union member and have the appropriate type", it appears that the excess property checker is not able to treat those properties as mutually exclusive.