However, is the resulting type of the | not actually an intersection, and that of & a union?
No. These concepts come from functional programming and type theory, so to understand them, it helps if you think of types in a way that's more in line with that.
Informally, think of a type as a set of all the instances of that type. For example, the string
type is conceptually a set of all concrete strings that you can construct, like "", "foo", "bar", "Hello, world!"
, etc. When you create an instance, it's like you are picking a single item from that set. If you come across some value, saying that it's of a certain type is like saying that it is contained in the set labeled by the type's name.
Now, when you define a union type number | string | boolean
, you are practically doing a union operation on those three sets; you are saying that a variable of that type can be a number or a string or a bool - i.e., it can take some value from any of those three sets. In other words, you are pulling from a set which is a union of the three.

As for the intersection types, imagine, again, informally, placing things in sets based on what operations (and properties) they support. In JavaScript, if you call a method on an object, any object that has a method with a matching name and the appropriate semantics will work. TypeScript uses structural typing, meaning that it essentially follows the same principle (types are defined based on members), except that it adds support for compile-time checking. So, an object is considered to be of a certain type if it has the structure (methods and properties) required by that type.
This means that you can take a bunch of instances (objects), and group them into sets based on the operations they support. Some will belong to more than one set, like in the image below. When you write Person & Serializable & Loggable
, you are restricting the set of possible values to only those that belong to all three sets simultaneously (and therefore support all these operations at the same time). I.e., you are allowing only those instances that are in their intersection.
