In the previous post, I said that when you ask a waiter “Is [some dish] vegan?” you would not want to hear the answer “I don’t know”.
But what if you ask about a dish that they do not serve? Imagine asking “Are Powidltatschkerln vegan?” somewhere outside Austria. I would totally expect to hear “I don’t know” as an answer. (They are not, by the way).
So, we might need a boolean with a third “I don’t know” option, after all…
Union Types
At the end of the previous part of this series,
I turned on “strict” type checking. That setting removes null
and undefined
from the possible values for all types (and it does more).
I would argue that this is the better default behavior for new projects. Without
strict null checks enabled, null
and undefined
are part of every set and
one cannot remove them. When we turn on strict, null
and undefined
are
removed from every set—but we can bring them back:
//use directly:
const vegan : boolean | null = null
//...or define a type alias
type NullableBoolean = boolean | null
const glutenFree : NullableBoolean = null
The |
here looks like the “logical or” operator of JavaScript—and you should
also read it as “or”. So, vegan
is a variable that is either a boolean
or null
and by defining the type alias NullableBoolean
we get a type that is a boolean or
the value null
.
Intersection Types
What if we use &
instead of |
? Can we do that too?
type NullableBoolean = boolean | null
const n : NullableBoolean = null
type MaybeDefinedBoolean = boolean | undefined
const m : MaybeDefinedBoolean = undefined
type Intersection = NullableBoolean & MaybeDefinedBoolean
const u1 : Intersection = true
const u2 : Intersection = false
const u3 : Intersection = null //ERROR
//Type 'null' is not assignable to type 'boolean'.(2322)
const u4 : Intersection = undefined //ERROR
//Type 'undefined' is not assignable to type 'boolean'.(2322)
Here we get a new type Intersection
that is both a NullableBoolean
and
a MaybeDefinedBoolean
.
Every value of that type must satisfy all restrictions of NullableBoolean
and
all restrictions of MaybeDefinedBoolean
. And there are only two values that
are both
boolean | null
and alsoboolean | undefined
at the same time: Only the values true
and false
satisfy both restrictions.
Back to Sets
When I first learned about union and intersection types (in another type system, a few years ago), I could not remember why “and” is and “intersection” while “or” is a “union”. The word “and” always sounded like it would add something, so when I thought of “and”, I also thought of “union”. Which is wrong, of course.
For me, it became easier to distinguish the names when I learned to think about the sets of possible values.
When a variable can hold either values from one type or values from another type, the set of possible values for this variable is the union of the other two sets.
Our NullableBoolean
can hold values from boolean
or from null
, so the
set of possible values is the union of boolean
and null
.
When, on the other hand, a value for a variable must satisfy all requirements from two or more types, the set of possible values for this variable must come from the intersection of the other sets.
Our type Intersection
must both be a NullableBoolean
and a MaybeDefinedBoolean
at the same time, and the only two values in this intersection of the two
sets are the “original” boolean values true
and false
.
Conclusion
Union types (A | B
) allow us to define types where the possible values are of either one
type or another type. The possible values come from the union of the original
sets. One simple thing we can do with unions is add more possible values (like
null
or undefined
) to an existing type.
Intersection types (A & B
) allow us to combine the restrictions of different other
types. The possible values come from the intersection of the original sets. One
simple thing we can do with them is remove possible values from an existing type.
I will get back to unions and intersections again in later posts—because one
can not only use them toadd null
or undefined
to a type in strict mode, but do more
interesting stuff with them.