Skip to content
Laviyx Learn

Try

TypeScript course menu

TypeScript Intersection Types: Combining Types with &

Learn TypeScript intersection types: combining object types with &, building types from reusable pieces, intersections versus interface extends, conflicting properties that become never, and intersections with unions.

Intermediate5 min readUpdated
On this page

An intersection type, written with &, combines several types into one that has all of their members. Where a union A | B means "A or B", an intersection A & B means "A and B at the same time".

Combining object types#

TypeScript
type HasId = { id: string };
type HasTimestamps = { createdAt: Date; updatedAt: Date };
type Post = { title: string; body: string };

type StoredPost = HasId & HasTimestamps & Post;

const post: StoredPost = {
  id: "p-1",
  title: "Learning TypeScript",
  body: "Intersections combine types.",
  createdAt: new Date("2026-10-01T00:00:00Z"),
  updatedAt: new Date("2026-10-24T00:00:00Z"),
};

console.log(post.id, post.title, post.updatedAt.toISOString().slice(0, 10));
Output
p-1 Learning TypeScript 2026-10-24

A StoredPost must have every property from all three types; leaving any out is an error. Small, reusable pieces like HasId and HasTimestamps can be mixed into many types.

Adding properties to an existing type#

Intersections are handy for "this type, plus a little more":

TypeScript
type User = { name: string; email: string };
type UserWithRole = User & { role: "admin" | "member" };

function welcome(user: UserWithRole): string {
  return `${user.name} (${user.role})`;
}

console.log(welcome({ name: "Asha", email: "asha@example.com", role: "admin" }));
Output
Asha (admin)

Intersection or interface extends?#

These two definitions produce types with the same members:

TypeScript
interface Animal { name: string }
interface Dog extends Animal { breed: string }

type AnimalT = { name: string };
type DogT = AnimalT & { breed: string };

const d1: Dog = { name: "Bruno", breed: "Labrador" };
const d2: DogT = d1;      // compatible: same shape
console.log(d2.breed);
Output
Labrador

Differences:

  • extends reports conflicting property types as an error at the declaration, which is clearer.
  • & works with any types, including unions and generic types, so it is more flexible.
  • Many teams use interface ... extends for object hierarchies and & when composing type aliases.

Conflicting properties#

If two intersected object types give the same property incompatible types, the property becomes never, so no value can satisfy it:

TypeScript
type A = { id: string };
type B = { id: number };
type AB = A & B;        // id: string & number, which is never

const x: AB = { id: "1" };
Compiler error
error TS2322: Type 'string' is not assignable to type 'never'.

Intersecting incompatible primitive types directly, such as string & number, also gives never.

Intersections with unions#

An intersection distributes over a union. This is useful to add common fields to every member of a discriminated union:

TypeScript
type Payment =
  | { method: "card"; last4: string }
  | { method: "upi"; upiId: string };

type PaymentRecord = Payment & { amount: number; paidAt: string };

const records: PaymentRecord[] = [
  { method: "card", last4: "4242", amount: 499, paidAt: "2026-10-20" },
  { method: "upi", upiId: "ravi@okbank", amount: 120, paidAt: "2026-10-21" },
];

const total = records.reduce((sum, r) => sum + r.amount, 0);
console.log(total, records.map((r) => r.method));
Output
619 [ 'card', 'upi' ]

Practice#

Practice exercise

Create reusable pieces Priced = { price: number } and Discountable = { discountPercent: number }, and use them to define SaleItem = { name: string } & Priced & Discountable. Write salePrice(item: SaleItem): number and print the sale price of a ₹1,200 item with a 25% discount.

Show solution
TypeScript
type Priced = { price: number };
type Discountable = { discountPercent: number };
type SaleItem = { name: string } & Priced & Discountable;

function salePrice(item: SaleItem): number {
  return item.price * (1 - item.discountPercent / 100);
}

const jacket: SaleItem = { name: "Jacket", price: 1200, discountPercent: 25 };
console.log(`${jacket.name}: ₹${salePrice(jacket)}`);
Output
Jacket: ₹900

Key takeaway#

Finished this lesson?