TYPESCRIPT

TypeScript Intersection Types: Syntax, Usage, and Examples

TypeScript intersection types allow developers to combine multiple types into one. They create a new type that merges the properties and methods of all included types. This powerful feature is part of TypeScript’s type system and offers greater control and precision in defining complex object structures.

Intersection types that TypeScript provides are especially useful when working with interfaces, object types, and functions that need to fulfill multiple roles. By understanding how and when to use them, you can build safer, more maintainable code.


What Are TypeScript Intersection Types?

Intersection types in TypeScript are created using the ampersand symbol (&). When two or more types are combined using this operator, the result is a new type that includes all the members from each source type.

type A = { a: number };
type B = { b: string };

type AB = A & B; // AB has both 'a' and 'b' properties

The new type AB must satisfy both A and B. This differs from union types (|), which accept one type or another, not necessarily both.


Why Use Intersection Types in TypeScript?

Using TypeScript intersection types helps when you want to:

  • Combine multiple types into a unified structure
  • Extend functionality while preserving type safety
  • Create complex objects with mixed capabilities
  • Avoid duplication by composing types instead of redefining them

Intersection types enable better abstraction in codebases that grow over time. Instead of reinventing types for similar objects, you can merge existing ones.


Basic Syntax of Intersection Types

The syntax for creating an intersection type is straightforward:

type Combined = TypeA & TypeB;

Here’s a basic example:

type Person = { name: string };
type Contact = { email: string };

type ContactPerson = Person & Contact;

const user: ContactPerson = {
  name: "Alex",
  email: "alex@example.com"
};

In this example, the user object must have both name and email properties. TypeScript enforces that the object meets all requirements from both Person and Contact.


Intersection Types vs Union Types

Understanding the difference between union and intersection is essential:

  • Union types (|): Allow either one type or another.
  • Intersection types (&): Require all types to be present simultaneously.

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

type U = A | B; // Accepts either A or B
type I = A & B; // Must satisfy both A and B

Union types are useful for flexibility; intersection types offer more structure. For instance, if you want to allow multiple possible shapes for a function argument, use a union. If the object must meet multiple contracts at once, use an intersection.


Using Interfaces with Intersection Types

Intersection types work seamlessly with interfaces. They let you combine multiple interfaces into one.

interface Drawable {
  draw(): void;
}

interface Clickable {
  click(): void;
}

type UIElement = Drawable & Clickable;

const button: UIElement = {
  draw: () => console.log("Drawing button"),
  click: () => console.log("Clicking button")
};

This allows you to describe objects with multiple behaviors without creating deeply nested inheritance chains.


Function Parameters and Intersection Types

TypeScript intersection types are especially useful for function parameters when a function should accept objects that combine several characteristics.

interface Logger {
  log(message: string): void;
}

interface Timestamped {
  timestamp: Date;
}

function logEvent(event: Logger & Timestamped) {
  console.log(`[${event.timestamp.toISOString()}]`);
  event.log("Event occurred.");
}

The logEvent function can only be called with an object that both logs messages and contains a timestamp.


Intersection Types with Classes

You can combine types from classes and interfaces using intersection types. This is particularly handy for extending behavior without altering class hierarchies.

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

interface Flyable {
  fly(): void;
}

type FlyingAnimal = Animal & Flyable;

const bird: FlyingAnimal = {
  name: "Eagle",
  fly: () => console.log("Flying high")
};

Although the class Animal is not extended directly, you can still merge its shape with other types dynamically.


Optional and Conflicting Properties

TypeScript allows merging optional properties in intersection types. However, if types contain conflicting property types, the result will not be assignable.

type A = { status: string };
type B = { status: number };

type C = A & B; // Error: 'string' is not assignable to 'number'

The conflict between status: string and status: number causes a type error because the compiler cannot resolve the contradiction.

When using TypeScript intersection type structures, be cautious of overlapping properties with different types.


Generic Intersection Types

Generics allow you to create reusable intersection types that work across different data shapes.

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

const result = merge({ id: 1 }, { name: "Test" });
// result has both 'id' and 'name' properties

This generic merge function returns a new object with the combined type of both input objects. TypeScript infers the intersection type automatically.


Intersection with Primitive Types

While intersection types work best with object types, they are technically allowed on any type. However, intersecting primitive types typically results in never (an impossible type).

type A = string & number; // never

There’s no value that can be both a string and a number at the same time, so the result is unusable. Stick to objects, interfaces, and custom types for meaningful intersections.


Intersection Types in Real-World Use Cases

Component Composition in Front-End Frameworks

When using frameworks like React or Vue with TypeScript, components often need props from multiple sources. Intersection types help compose them clearly.

type OwnProps = { id: string };
type ReduxProps = { dispatch: Function };

type Props = OwnProps & ReduxProps;

You can then use Props in your component without repeating the individual type definitions.

Combining API Response Shapes

Sometimes an API returns partial responses or combined data from multiple sources. You can describe these compound types using intersections.

type User = { id: number; username: string };
type Profile = { bio: string; avatar: string };

type FullUser = User & Profile;

This helps maintain clarity and type safety when consuming composite data structures.


When to Avoid Intersection Types

While powerful, TypeScript intersection types are not always the best solution. Avoid them in these scenarios:

  • When the resulting type is too complex to understand or debug
  • If properties from source types conflict
  • When using primitives or unrelated shapes

It’s better to use composition, conditional types, or utility types if intersection logic gets too convoluted.


Related Utility Types

TypeScript also provides utility types that work well with intersections:

  • Partial<T> — makes all properties optional
  • Pick<T, K> — selects a subset of properties
  • Omit<T, K> — removes specified keys

You can mix these with intersection types to build more expressive and flexible shapes.

type Config = { url: string; timeout: number };
type PartialConfig = Partial<Config> & { url: string };

Here, timeout is optional, but url remains required.


TypeScript intersection types offer a powerful way to compose multiple types into one. You can use them to enforce that an object or function satisfies all included types, giving your code better structure, safety, and reusability.

Learn TypeScript for Free
Start learning now
button icon
To advance beyond this tutorial and learn TypeScript by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH

Reach your coding goals faster