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.
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.