Search⌘ K

Intersections and Composition

Explore how to compose complex TypeScript types using intersections, enabling you to combine multiple interfaces, type aliases, and inline types. Learn to model objects with multiple capabilities, handle type conflicts, and apply intersections beyond objects for more precise typing.

From “either/or” to “both/and”

We’ve already seen how to model choices in TypeScript using union types. But in real-world systems, we often need to model combinations—types that require multiple capabilities or concerns to come together.

Interfaces gave us one way to do this: with extends, we can inherit from a single base shape. But when we want to combine anything—multiple interfaces, type aliases, or inline types—we need a more flexible tool.

That tool is the intersection type, written with &. It is TypeScript’s way of saying: “This value must be everything these types require.”

Declaring an intersection type

An intersection type lets us build a new type that satisfies all the members of multiple types at once. The syntax TypeA & TypeB creates a new type that must match every member in the list. Think of it as logical and at the type level.

TypeScript 5.8.3
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true
}
}

Explanation:

  • Lines 1–2: We define two separate object shapes.

  • Line 4: FullUser merges both. Now any object of this type must have id, name, canEdit, and canDelete.

  • Lines 6–11: A compliant object must satisfy every field; omit one and the compiler shuts us down.

Intersections vs. extends: What’s the difference?

Here’s a quick refresher: Interfaces support extends for inheritance.

interface AdminUser extends User {
isSuperAdmin: boolean;
}
Extending the User interface to create a new AdminUser type with an additional isSuperAdmin property

We can achieve the same result plus more flexibility with an intersection:

type AdminUser = User & { isSuperAdmin: boolean };

The key difference is that extends only ...