Type intersections


& in TypeScript is called the intersection operator.

Why tho? If you’re familiar with set intersections it might seem like & works exactly the wrong way around… like, intersecting the sets {1, 2, 3} and {2, 3, 4} gives you {2, 3} — it’s the subset of elements that exist in both sets.

But in Typescript, { foo: string } & { bar: number } gives { foo: string, bar: number } — we get all properties of either type. Isn’t that more like a union?

Well

No.

There’s a very formal reason why the “type intersection” is called as such, and it has to do with the Liskov Substitution Principle.

Take a look at the following function definitions:

const foo = (x: { foo: string }) => x.foo;
const bar = (x: { bar: number }) => x.bar;

foo takes Foos, and bar takes Bars, but our intersection type { foo: string } & { bar: number } can be passed to either function.

So if you imagine { foo: string } and { bar: number } as circles on a Venn Diagram, then our intersection type is like the middle part. Our foobar can go to the foo club and the bar club, so to speak, because the foobar is a subtype of the foos and a subtype of the bars.

The Venn Diagram and it’s intersection in this case doesn’t show a subset relationship, but rather a subtype relationship!

It is kind of funny tho how the type with more properties will be a subtype of the type with fewer properties but that’s just what follows from the above.

And what follows from that is that the empty type {} isn’t actually a subtype of any other type, while the empty set {} is a subset of every set. The “empty set” equivalent of types would be a sort of impossible type that contains all properties, and where each property can be anything.

In typescript, that type is called never.