Intersection types

Like union types, intersection types allow us to combine the properties of existing primitive and custom types to make composites.

Creating an intersection

Say you have the following three types:

type IConcert = {
  date: number;
  location: string;
  band: string;
};

type IConference = {
  date: number;
  location: string;
  keynoteSpeaker: string;
};

type IMeeting = {
  date: number;
  location: string;
  agenda: string[];
};

Each type corresponds to a different event and has two properties in common with the other events: date and location.

Rather than repeat these properties for each individual type, we could create a general IEvent type and apply this as an intersection to each of the individual event types:

// The common event type
type IEvent = {
  date: number;
  location: string;
};
// The intersection

type IConcert = IEvent & {
  band: string;
};

type IConference = IEvent & {
  keynoteSpeaker: string;
};

In the case of interfaces, instead of using & we would write interface IConcert extends IEvent

Alternative method

There is another equivalent way of intersecting the types. We could first define IConcert and IConference as their own types (without extends or &) and then intersect with, e.g., type IConcert = SelfStandingConcertType & IEvent.

Benefits of intersections

  • It is more concise and we do not repeat ourselves needlessly
  • Common properties can be modelled in one place which makes updates and changes much easier: we do not have to change multiple type declarations, just change the ‘master’ type that is intersected with the variants.
  • It is more readable: we can see which properties are unique to the type without having to parse repeated properties.

Set theory: understanding errors

With intersections we literally use the & operator which discloses that the logic is equivalent to logical AND: a member of the intersection must have the properties of both types. In the case of primitive values this is impossible or, more accurately, it results in an empty set because, for example, string and boolean do not share any common values. This means you will get an error if you assign an intersection type to a value that does not have all the features of each custom type in the intersection.