Naming of TypeScript union and intersection types
Asked Answered
W

9

101

I can't understand the logic behind the terms intersection types and union types in TypeScript. I'm thinking of interfaces (or classes) as sets of properties.

The logical conjunction operator & is equivalent to intersection in set theory, defined as:

The intersection of two sets A and B, is the set containing all elements of A that also belong to B

In TypeScript, an Intersection Type is also built using the & operator and is defined as:

The intersection type of interface Colorful and interface Circle is a new type that has all the members of Colorful and Circle

This is the exact opposite of how intersection is defined in mathematics and set theory.

I'm sure there is another way of looking at it, but I cannot figure it out.

Wasteful answered 9/8, 2016 at 16:21 Comment(2)
The members of a type T | U is members(T) | members(U) and similarly members of T & U are members of both T and U so are in the intersection of members(T) and members(U).Orlosky
∨ := ∪ (union), v means or, so union is or, which is represented with | in typescript.Herat
S
61

Here's another way to think about it. Consider four sets: Blue things, red things, big things, and small things.

If you intersect the set of all blue things and all small things, you end up with the union of the properties -- everything in the set has both the blue property and the small property.

But if you took the union of blue small things and red small things, only the smallness property is universal in the resulting set. Intersecting "blue small" with "red small" produces "small".

In other words, taking the union of the domain of values produces an intersected set of properties, and vice versa.

In image form: enter image description here

Sophy answered 9/8, 2016 at 18:11 Comment(11)
Thanks, it's very descriptive, and exactly points out where I was wrong: I was thinking in sets of properties, not sets of instances.Wasteful
Why would you think of a type as a set of instances? Instances of what, the type? What type.. ? This is circular reasoning no?Lundeen
Grouping extant objects into named classifications (which we now call "types") is something humans have been doing for hundreds of thousands of years.Sophy
Isn't it our goal to define what that classification is, what characterizes it, the properties and methods it has?Lundeen
Thinking from a user perspective, it's clearer to say "A implements either B or C" and "A implements both B and C" than "We are sure that A has properties that are both in B and C" and "A has any properties that are either in B or C".Desiderate
This is circular reasoning. To make the example accurate, you'd have to consider that things may have other properties besides just 'blue' or 'small'... For example let's say some things have a 'transparent' property. So the intersection of blue things and small things does not give you the union of all properties which those things can have; since some items in the intersection could be missing that third 'transparent' property, for example. Some of the small blue things will not be transparent.Impugn
The statement "The union of these sets have the intersection of its properties" makes no sense! You could also say "The intersection of these sets have the intersection of its properties!" That's also true and also carries no information.Impugn
wow, thank you! it does give some peace of mind :)Twentytwo
So the intersection ends up being a union. And the union ends up being an empty intersection? That kind of proves to me how poor the choice of terms was. BTW, logical operations on Javascript constructors always yield 0: (Object & Object) === 0, (Object | Object) === 0 Typescript must be making that up out of nowhere.Hopfinger
This is the terminology CS type theorists have been since the 70'sSophy
Instead of blue/red/big/small, I like to think of cat/dog/fast/slow. The intersection or union types are describing a set of kinds. If we union a set of multiple of cat types with a set of multiple dog types might get { cat, cat, cat, dog, dog }. None of these have properties of both cats and dogs. If we intersect the two distinct types of { cat } and { dog }, we'd get { }, nothing in common. We could mix cat properties and dog properties together in a new "CatDog" type-- but that would not be the intersection of types, it would be the union of their properties.Dilettante
H
21

The type A | B refers to objects which are either A or B. In other words, values of such type are drawn from the union of values for A and values for B.

The type A & B refers to objects which are both A and B. In other words, values of such type are drawn from the intersection of values for A and values for B.

The naming and semantics are identical in other languages such as C++.

Hesperian answered 9/8, 2016 at 16:33 Comment(2)
To clear OPs misunderstanding: types need to be viewed as open descriptions (lower limit of properties), not as closed ones (exact set of properties). In maths, a type is a set of constraints or formula for an infinitely large number of possible elements to choose from. This is the origin of polymorphy. An element might also satisfy other constraints which are not specified in the type. A bigger set of constraints A & B means a smaller-equal set of elements can satisfy them. A | B weakens constraints. Imagine encoding sets as bitvectors, each index representing a different element.Steelhead
@Steelhead The comment section is meant to request updates/clarification of the answer. I don't think your long verbose comment is appropriate here. If you want to elaborate on your own idea, consider making it into your own answer. Thanks.Razorbill
A
19

You must not think of types as sets of object properties in this case. We can avoid the confusion about how union and intersection types work by looking at scalar variables and their sets of permissible values (instead of objects):

type A = 1 | 2
type B = 2 | 3
type I = A & B
type U = A | B

let a: A
let b: B
let i: I
let u: U

a = 1
a = 2
a = 3 // <- error

b = 1 // <- error
b = 2
b = 3

i = 1 // <- error
i = 2
i = 3 // <- error

u = 1
u = 2
u = 3

Here the terms "union" and "intersection" correspond exactly to the set theory terms when applied to the sets of permissible values.

Applying the notion of permissible values (instances) to object types is a bit trickier (because the set theory analogy doesn't hold well):

type A = {
  x: number
  y: number
}

type B = {
  y: number
  z: number
}

type I = A & B
type U = A | B
  • A variable of type A can hold object instances with properties x and y (and no other properties).
  • A variable of type B can hold object instances with properties y and z (and no other properties).
  • In set theory the intersection of the two sets of object intances above is empty. However, a variable of intersection type I can hold objects with the properties of type A AND those of type B (i.e. x, y, and z; hence the & symbol) which corresponds to the union of properties of the two types (hence the confusion).
  • In set theory the union of the two sets of object intances above does not include objects with all three properties. However, a variable of union type U can hold objects with the properties of type A OR those of type B (logical OR, not XOR, i.e. x and y, y and z, or x, y, and z; hence the | symbol) which implies that the intersection of properties of the two types (y in our example) is guaranteed to be present (hence the confusion).
let i: I
let u: U

i = { x: 1, y: 2 };         // <- error
i = { y: 2, z: 3 };         // <- error
i = { x: 1, y: 2, z: 3 };

u = { x: 1, y: 2 };
u = { y: 2, z: 3 };
u = { x: 1, y: 2, z: 3 };
Aquila answered 11/5, 2020 at 15:13 Comment(0)
S
11

The confusion here probably stems from how we imagine the sets, namely, thinking of the intersection/union as involving the members of types as opposed to the types themselves. I put together a graphic that hopefully clarifies the concept:

Union/Intersection diagram

Shillong answered 14/3, 2020 at 18:52 Comment(2)
This answer doesn't really explain how or why the Venn-diagram showing a set union is being used to describe an intersection type (and vice-versa in the second row).Natural
@Natural Because a union means it can be either an A object, a B object, or an AB object. If it were an A object, then B members wouldn't exist, and vice versa, therefore neither A nor B exclusive members can be guaranteed. Hope that makes sense.Shillong
S
3

I also had the same question and couldn't understand how could it be seen in the opposite way. After reading the answers, I think I could explain it in the linguistic aspect providing different meanings of the two words and giving a room for the opposite naming approaches.

Compare the following meanings of word intersect:

The orbit of this comet intersects the orbit of the Earth.

In this sentence intersect means to cross at a point or set of points. Think of two things having something common (e.g. a point), and otherwise different. That's what is called intersection in math and SQL.

We need to pinpoint the place where maximum achievable conservation intersects with the highest potential financial return.

Here intersect means to come together and have an effect on each other, like two things becoming components of one new cool thing. That's the meaning of the word in TypeScript.

In a similar way you can think of union as an act of joining different things together in a loose sense - that is the meaning of union in math and SQL; but it can mean not just joining but joining together with a common interest or purpose which corresponds to the meaning of union in TypeScript.

Inspired (don't ask me why) by different translations of intersect into Russian: пересекать (also to cross) and скрещивать (also to crossbreed).

Sarrusophone answered 20/10, 2020 at 21:23 Comment(0)
H
3

They just updated the documentation the other day, and now it provides a clarifying description with a simple example:

It might be confusing that a union of types appears to have the intersection of those types’ properties. This is not an accident - the name union comes from type theory. The union number | string is composed by taking the union of the values from each type. Notice that given two sets with corresponding facts about each set, only the intersection of those facts applies to the union of the sets themselves. For example, if we had a room of tall people wearing hats, and another room of Spanish speakers wearing hats, after combining those rooms, the only thing we know about every person is that they must be wearing a hat.

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types

Herat answered 28/12, 2021 at 22:20 Comment(0)
M
1

Think of it this way...

Intersection Types (A & B)

In the universe of objects, only those who are compatible with both A AND B are part of the domain of the intersection type; and therefore contain all properties of A and B (the union of both sets of properties). In other words, if the objects are sitting in the intersection of A and B, they possess all properties (the union) of both A and B.

Union Types (A | B)

In the universe of objects, only those who are compatible with either A OR B are part of the domain of the union type; and therefore contain all properties of A or all properties of B, potentially having some or no properties in common between A and B. In other words, if the objects are sitting in the union of A and B, they can either possess all properties of A or all properties of B, and potentially common properties (the intersection) of A and B.

Merrell answered 27/7, 2022 at 0:51 Comment(2)
This doesn't make sense. OK, the union of two sets contains the intersection of those two sets... But the intersection of two sets also contains the intersection of those two sets... Since every set is a subset of itself. That would be like saying; let's call the set of all living creatures cats because a subset of those living creatures are cats.Impugn
Specifically, what it is that doesn't make sense to you?Merrell
T
-1
type Head = {
  skin: string, 
  bones: string, 
  nouse: number, 
  eyes: number, 
  ears: number 
}

type Body = {
  skin: string, 
  bones: string, 
  arms: number, 
  foots: number
}

type Frankenstein = Head | Body

let frank: Frankenstein

`1 rule (only Head)`

frank = {skin: 'green', bones: 'skull', nouse: 1, eyes: 2, ears: 2}

`2 rule (only Body)`

frank = {skin: 'gray', bones: 'skeleton', arms: 2, foots: 2}

`3 rule (Body and Head all together)`
 
frank = {
  skin: 'green', 
  bones: 'skull', 
  nouse: 1, 
  eyes: 2, 
  ears: 2, 
  arms: 2, 
  foots: 2
}

`4 rule (Frank without arms or foots or ears or ...)`

frank = {
  skin: 'green', 
  bones: 'skull', 
  nouse: 1, 
  eyes: 2, 
  ears: 2,
  foots: 2
 }

frank = {
  skin: 'green', 
  bones: 'skull', 
  nouse: 1, 
  eyes: 2, 
  ears: 2, 
  arms: 2
}

frank = {
  skin: 'green',
  bones: 'skull',
  nouse: 1,
  eyes: 2,
  arms: 2, 
  foots: 2
}

`-1 rule (he can't exist without general parts)`

frank = {
  bones: 'skull',
  nouse: 1,
  eyes: 2,
  ears: 2,
  foots: 2} //error

frank = {
  skin: 'green',
  nouse: 1, 
  eyes: 2,
  ears: 2,
  arms: 2} //error

`-2 rule (and the MOST NOTABLY he can not exist without full kit of one of 
his parts, why - ask his best friend - TypeScript)`

frank = {
  skin: 'green',
  bones: 'skull',
  eyes: 2,
  ears: 2,
  foots: 2} //error

frank = {
  skin: 'green',
  bones: 'skull',
  nouse: 1,
  eyes: 2,
  arms: 2
} //error
Threecolor answered 23/12, 2020 at 21:48 Comment(0)
R
-1

This isn't a problem if you consider what the subject you're talking about. It's just the intersection of sets vs properties.

Razorbill answered 7/4, 2024 at 22:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.