Union types are fairly popular in TypeScript. You might have already used them multiple times. Intersection types are slightly less common. They seem to cause a little bit more confusion.

Did you ever wonder where do those names come from? While you might have some intuition about what a union of two types is, the intersection is usually not understood well.

After reading this article, you will have a better understanding of those types which will make you more confident when using them in your codebases.

## Simple union types

Union type is very often used with either `null`

or `undefined`

.

```
const sayHello = (name: string | undefined) => { /* ... */ };
```

For example, the type of `name`

here is `string | undefined`

which means that either a `string`

OR an `undefined`

value can be passed to `sayHello`

.

```
sayHello("milosz");
sayHello(undefined);
```

Looking at the example, you can intuit that a union of types `A`

and `B`

is a type that accepts both `A`

and `B`

values.

## Union and intersection of object types

This intuition also works for complex types.

```
interface Foo {
foo: string;
xyz: string;
}
interface Bar {
bar: string;
xyz: string;
}
const sayHello = (obj: Foo | Bar) => { /* ... */ };
sayHello({ foo: "foo", xyz: "xyz" });
sayHello({ bar: "bar", xyz: "xyz" });
```

`Foo | Bar`

is a type that has either all required properties of `Foo`

OR all required properties of `Bar`

. Inside `sayHello`

it's only possible to access `obj.xyz`

because it's the only property that is included in both types.

What about the intersection of `Foo`

and `Bar`

, though?

```
const sayHello = (obj: Foo & Bar) => { /* ... */ };
sayHello({ foo: "foo", bar: "bar", xyz: "xyz" });
```

Now `sayHello`

requires the argument to have both `foo`

AND `bar`

properties. Inside `sayHello`

it's possible to access both `obj.foo`

, `obj.bar`

and `obj.xyz`

.

Hmm, but what does it have to *intersection*? One could argue that since `obj`

has properties of both `Foo`

and `Bar`

, it sounds more like a union of properties, not intersection. Similarly, a union of two object types gives you a type that only has the intersection of properties of constituent types.

It sounds confusing. I even stumbled upon a GitHub issue in TypeScript repository ranting about naming of these types. To understand the naming better we need to look at types from a different perspective.

## Set theory

Do you remember a concept called *sets* from math classes? In mathematics, a set is a collection of objects (for example numbers). For example, `{1, 2, 7}`

is a set. All positive numbers can also form a set (an infinite one).

Sets can be added together (a **union**). A union of `{1, 2}`

and `{4, 5}`

is `{1, 2, 4, 5}`

.

Sets can also be intersected. **Intersection** of two sets is a set that only contains those numbers that are present in both sets. So, an intersection of `{1, 2, 3}`

and `{3, 4, 5}`

is `{3}`

.

Let's imagine two sets: `Squares`

and `RedThings`

.

The union of `Squares`

and `RedThings`

is a set that contains both squares and red things.

However, the intersection of `Squares`

and `RedThings`

is a set that only contains **red squares**.

## Relationship between types and sets

Computer science and mathematics overlap in many places. One of such places is type systems.

A type, when looked at from a mathematical perspective, is a **set of all possible values of that type**. For example the `string`

type is a set of all possible strings: `{'a', 'b', 'ab', ...}`

. Of course, it's an infinite set.

Similarly, `number`

type is a set of all possible numbers: `{1, 2, 3, 4, ...}`

.

Type `undefined`

is a set that only contains a single value: `{ undefined }`

.

What about object types (such as interfaces)? Type `Foo`

is a **set of all object that contain foo and xyz properties**.

## Understanding union and intersection types

Armed with this knowledge, you're now ready to understand the meaning of union and intersection types.

Union type `A | B`

represents a set that is a union of the set of values associated with type `A`

and the set of values associated with type `B`

.

Intersection type `A & B`

represents a set that is an intersection of the set of values associated with type `A`

and the set of values associated with type `B`

.

Therefore, `Foo | Bar`

represents **a union** of the set of objects having `foo`

and `xyz`

properties and the set of objects having `bar`

and `xyz`

. Objects belonging to such set all have `xyz`

property. Some of them have `foo`

property and the others have `bar`

property.

`Foo & Bar`

represents **an intersection** of the set of objects having `foo`

and `xyz`

properties and the set of objects having `bar`

and `xyz`

. In other words, the set contains objects that belong to sets represented by both `Foo`

and `Bar`

. Only objects that have all three properties (`foo`

, `bar`

and `xyz`

) belong to the intersection.

## Real-world example of intersection type

Union types are quite widespread so let's focus on an example of an intersection type.

In React, when you declare a class component, you can parameterise it with thy type of its properties:

```
class Counter extends Component<CounterProps> { /* ... */ }
```

Inside the class, you can access the properies via `this.props`

. However, the type of `this.props`

is not simply `CounterProps`

, but:

```
Readonly<CounterProps> & Readonly<{ children?: ReactNode; }>
```

The reason for this is that React components can accept children elements:

```
<Counter><span>Hello</span></Counter>
```

The children element tree is accessible to the component via `children`

prop. The type of `this.props`

reflects that. It's an intersection of (readonly) `CounterProps`

and a (readonly) object type with an optional `children`

property.

In terms of sets, it's an intersecion of the set of objects that have properties as defined in `CounterProps`

and the set of objects that have optional `children`

property. The result is a set of objects that have both all properties of `CounterProps`

and the optional `children`

property.

## Summary

That's it! I hope this article helps you wrap your head around union and intersection types. As it's often the case in computer science, understanding the fundamentals makes you better at grasping programming concepts.

## Want to learn more?

Did you like this TypeScript article? I bet you'll also like my course!

## Want to learn more?

Did you like this TypeScript article? I bet you'll also like my book!

## Top comments (5)

This was a great article! Thank you.

I’m still not 100% sure I understood the union of 2 sets of objects.

So if you have

`Foo | Bar`

, wouldn’t it be similar to saying: just collect the objects from both sets?Then, the intersection would result in

`{ { xyz, foo }, { xyz, bar } }`

, right? Then, how can one infer that the actually resulted set would only be`{ xyz }`

? 🤔Thanks!

Union would indeed contain all objects from both sets. However, the only thing we can know for sure about these objects is that they must contain the

`xyz`

property. Therefore, the type is`{ xyz: string }`

.TypeScript has the concept of type assignability. An object type is assignable to

`{ xyz: string }`

type even if it has some excess properties (there are exceptions, though - see here). So, all objects from both union members are assignable to`{ xyz: string }`

type.I think I finally understood it!

So it’s typescript’s magic that translates a union that resulted from a mathematical point of view into a single type that all the other types are assignable to.

So, without typescript, I’d get

`{ { xyz, foo }, { xyz, bar } }`

, but after typescript weighs in, the resulted type will only be`{ xyz: string }`

.I hope I got it right.

Thank you!

Yeah, I think you've got it right :)