TYPESCRIPT

TypeScript Mixin: Syntax, Usage, and Examples

TypeScript mixins allow you to reuse functionality across multiple classes without using traditional inheritance. They provide a way to compose behavior dynamically, making code more modular and maintainable. Mixins in TypeScript are particularly useful when multiple classes need to share logic but do not fit into a strict class hierarchy.

How to Use TypeScript Mixins

A mixin is a function that adds properties or methods to a class. Since TypeScript does not support multiple inheritance, mixins work by copying properties from one class to another.

Basic Mixin Structure

type Constructor<T = {}> = new (...args: any[]) => T;

function Timestamped<T extends Constructor>(Base: T) {
  return class extends Base {
    timestamp = new Date();
  };
}

class Message {
  content: string;
  constructor(content: string) {
    this.content = content;
  }
}

const TimestampedMessage = Timestamped(Message);
const message = new TimestampedMessage("Hello");

console.log(message.content); // "Hello"
console.log(message.timestamp); // Current timestamp

When to Use TypeScript Mixins

Mixins are useful when you need to:

  1. Share methods across unrelated classes without modifying their prototypes.
  2. Extend class functionality dynamically at runtime.
  3. Avoid deep inheritance trees by composing behavior flexibly.

Examples of TypeScript Mixins

Using Multiple Mixins

You can combine multiple mixins using function composition.

function Loggable<T extends Constructor>(Base: T) {
  return class extends Base {
    log() {
      console.log(`Logging: ${JSON.stringify(this)}`);
    }
  };
}

class Task {
  description: string;
  constructor(description: string) {
    this.description = description;
  }
}

const LoggableTask = Loggable(Task);
const task = new LoggableTask("Complete project");
task.log();
// Output: Logging: {"description":"Complete project"}

TypeScript Class Mixins

The applyMixins function allows multiple mixins to be applied to a class.

function applyMixins(targetClass: any, mixinClasses: any[]) {
  mixinClasses.forEach(mixin => {
    Object.getOwnPropertyNames(mixin.prototype).forEach(name => {
      targetClass.prototype[name] = mixin.prototype[name];
    });
  });
}

class Printable {
  print() {
    console.log("Printing...");
  }
}

class Savable {
  save() {
    console.log("Saving...");
  }
}

class Report {}
applyMixins(Report, [Printable, Savable]);

const report = new Report() as Report & Printable & Savable;
report.print(); // "Printing..."
report.save(); // "Saving..."

TypeScript Mixin Abstract Class

A mixin can extend an abstract class to enforce structure while allowing flexibility.

abstract class DataModel {
  abstract save(): void;
}

function TrackChanges<T extends Constructor<DataModel>>(Base: T) {
  return class extends Base {
    changes: string[] = [];
    recordChange(change: string) {
      this.changes.push(change);
    }
  };
}

class UserModel extends DataModel {
  save() {
    console.log("User saved.");
  }
}

const TrackedUserModel = TrackChanges(UserModel);
const user = new TrackedUserModel();
user.recordChange("Updated email");
console.log(user.changes); // ["Updated email"]
user.save(); // "User saved."

TypeScript Mixin Constructor

You can enforce a specific constructor structure using an interface.

interface Named {
  name: string;
}

function NamedMixin<T extends Constructor<Named>>(Base: T) {
  return class extends Base {
    getDisplayName() {
      return `User: ${this.name}`;
    }
  };
}

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

const NamedPerson = NamedMixin(Person);
const person = new NamedPerson("Alice");
console.log(person.getDisplayName()); // "User: Alice"

TypeScript Mixins Example

The following example combines multiple mixins with different functionality.

function CanFly<T extends Constructor>(Base: T) {
  return class extends Base {
    fly() {
      console.log("Flying...");
    }
  };
}

function CanSwim<T extends Constructor>(Base: T) {
  return class extends Base {
    swim() {
      console.log("Swimming...");
    }
  };
}

class Superhero {}
applyMixins(Superhero, [CanFly, CanSwim]);

const hero = new Superhero() as Superhero & { fly: () => void; swim: () => void };
hero.fly(); // "Flying..."
hero.swim(); // "Swimming..."

Learn More About TypeScript Mixins

Mixin vs. Inheritance

Unlike traditional class inheritance, where a child class extends a single parent class, mixins allow multiple behaviors to be merged into one class. This prevents deep class hierarchies and allows more modular code reuse.

Using Mixins in TypeScript Libraries

Many libraries use mixins to extend functionality dynamically. For example, UI frameworks like Vue and React use mixins to share component logic.

function Reactive<T extends Constructor>(Base: T) {
  return class extends Base {
    reactiveData = {};
  };
}

class Component {}
const ReactiveComponent = Reactive(Component);
const comp = new ReactiveComponent();
comp.reactiveData = { theme: "dark" };
console.log(comp.reactiveData); // { theme: "dark" }

Limitations of Mixins

  • Mixins can make code harder to debug if too many behaviors are added.
  • They do not support proper method overriding, so conflicts may arise when two mixins define the same method.
  • Type inference might become complex when applying multiple mixins.

TypeScript mixins provide a powerful way to share behavior across multiple classes without deep inheritance trees. You can use them to extend functionality dynamically, create reusable logic, and simplify code structure.

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