TypeScript

Intersections in TypeScript – Complete Guide with Examples

Excellent follow-up ✅ — after unions, the natural next step is intersections.
Where unions mean “A or B”, intersections mean “A and B”.
They’re crucial for combining types, enforcing multiple constraints, and building reusable abstractions in TypeScript.

Here’s a deep, unique TypeScript article with practical examples.


TypeScript has two powerful operators for building complex types:

  • Union (|) → a value can be one of many types.
  • Intersection (&) → a value must satisfy all given types simultaneously.

In this article, we’ll dive into intersections.


1. What is an Intersection Type?

An intersection combines multiple types into one.
The resulting type must have all the members of every type.

type A = { id: number };
type B = { name: string };

type AB = A & B;

const obj: AB = { id: 1, name: "Alice" }; // ✅ must have both

👉 You can think of intersections like set theory:

  • Union → all elements from both sets.
  • Intersection → only elements that belong to both sets at once.

2. Intersection with Objects

Intersections are commonly used to compose object shapes.

type Timestamps = { createdAt: Date; updatedAt: Date };
type User = { id: number; name: string };

type UserWithTimestamps = User & Timestamps;

const u: UserWithTimestamps = {
  id: 1,
  name: "Alice",
  createdAt: new Date(),
  updatedAt: new Date()
};

👉 This allows reuse of smaller types across models.


3. Intersection with Interfaces

Works the same with interface:

interface Logger { log: (msg: string) => void }
interface ErrorHandler { handleError: (err: Error) => void }

type Service = Logger & ErrorHandler;

const s: Service = {
  log: (m) => console.log(m),
  handleError: (e) => console.error(e.message)
};

4. Functions with Intersection Types

Intersections can describe functions with multiple capabilities:

type Fn1 = (x: number) => string;
type Fn2 = (y: string) => number;

type Combined = Fn1 & Fn2; // function must support BOTH

declare const f: Combined;

let a: string = f(42);     // ✅ from Fn1
let b: number = f("text"); // ✅ from Fn2

👉 Rare but powerful for overloaded functions.


5. Intersection with Generics

Generics + intersections = reusable constraints.

function merge<T, U>(a: T, b: U): T & U {
  return { ...a, ...b };
}

const user = { id: 1, name: "Alice" };
const timestamps = { createdAt: new Date() };

const result = merge(user, timestamps);
// result: { id: number; name: string; createdAt: Date }

6. Intersection with Utility Types

You can combine intersections with built-in utilities:

type User = { id: number; name: string };
type Admin = { role: "admin" };

type AdminUser = User & Admin;

Or with Partial and Readonly:

type ImmutableOptionalUser = Readonly<Partial<User>>;

7. Real-World Examples

(a) React Component Props

Sometimes you want to reuse base props and extend them.

type BaseProps = { disabled?: boolean };
type ButtonProps = BaseProps & { label: string; onClick: () => void };

const Button = ({ label, disabled, onClick }: ButtonProps) => (
  <button disabled={disabled} onClick={onClick}>{label}</button>
);

(b) Angular Component Models

type Auditable = { createdAt: Date; updatedAt: Date };
type Product = { id: string; name: string };

type ProductModel = Product & Auditable;

@Component({...})
export class ProductCard {
  @Input() product!: ProductModel;
}

(c) Vue with Composition API

type Size = { size: "small" | "large" };
type Color = { color: "red" | "blue" };

type ButtonProps = Size & Color;

export default defineComponent({
  props: {
    size: { type: String as PropType<"small" | "large">, required: true },
    color: { type: String as PropType<"red" | "blue">, required: true }
  }
});

(d) Node.js API Models

type DbEntity = { id: string };
type Timestamps = { createdAt: Date; updatedAt: Date };
type User = { name: string; email: string };

type UserEntity = DbEntity & Timestamps & User;

8. Intersection vs Union

| Feature | Union (|) | Intersection (&) |
|———|————-|———————|
| Meaning | Value can be A OR B | Value must be A AND B |
| Example | string | number"hi" or 42 | {id} & {name} → must have both |
| Usage | Flexibility (alternative shapes) | Composition (combine features) |


9. Pitfalls of Intersections

  1. Conflicting properties type A = { x: string }; type B = { x: number }; type C = A & B; // ❌ x cannot be string AND number → Results in never for x.
  2. Too many intersections = complexity
    Overusing intersections can make code hard to maintain.

10. Best Practices

  • ✅ Use intersections to compose models (User & Timestamps).
  • ✅ Combine with generics for reusable patterns (merge<T, U>).
  • ✅ Use in React/Angular/Vue props when extending base props.
  • ❌ Avoid conflicting property names.
  • ❌ Don’t intersect too many types — readability suffers.

11. Conclusion

  • Intersection (&) enforces all conditions at once.
  • Best for composition, code reuse, and strong modeling.
  • Works with objects, functions, generics, and utility types.
  • Use unions when you want choice, intersections when you want combination.

👉 Mastering both unions and intersections allows you to model real-world data precisely in TypeScript.


Related posts
TypeScript

Literals in TypeScript: String, Number, Boolean, Template, and Compound Literals

Literals are one of the fundamental building blocks of TypeScript programming. They represent fixed…
Read more
TypeScript

Utility Types in TypeScript: Pick, Omit, Partial, Required, Readonly, Record...

✅ — Utility Types are one of the most powerful features of TypeScript, but also one of the most…
Read more
TypeScript

Complete TypeScript Tutorial Online: Master TypeScript in 2025

TypeScript has revolutionized modern web development by bringing static typing to JavaScript, making…
Read more