DEV Community

Cover image for The Mixin Pattern – Borrow, Don’t Inherit
Md Enayetur Rahman
Md Enayetur Rahman

Posted on

The Mixin Pattern – Borrow, Don’t Inherit

A distilled summary of the “Mixin Pattern” chapter in Learning Patterns by Lydia Hallie & Addy Osmani, with pragmatic examples you can drop into production today.


1  Why Mixins?

“Inheritance is a powerful tool, but it’s also a tight coupling. Mixins let us compose features without locking ourselves into a hierarchy.” – Learning Patterns

The authors argue that composition beats inheritance when the relationship between features is has‑a rather than is‑a. Mixins add behaviour to any class without forcing a shared ancestor.

At a glance

  • Goal – Reuse behaviour across unrelated classes.
  • Mechanism – Copy or wrap methods/props from one object into another.
  • Benefit – Avoid deep class chains and the fragility of multiple inheritance.

2  Implementing a Mixin in Modern JavaScript / TypeScript

2.1 Shallow copy (Object.assign)

const sayHiMixin = {
  sayHi() {
    console.log(`Hi, I’m ${this.name}`);
  }
};

class User {
  constructor(public name: string) {}
}

// ① copy the mixin methods onto User.prototype
Object.assign(User.prototype, sayHiMixin);

new User('Farzana').sayHi(); // ➜ Hi, I’m Farzana
Enter fullscreen mode Exit fullscreen mode

2.2 Functional class mixin (safer with typing)

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

function TimeStamped<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    createdAt = new Date();
  };
}

class Article {
  constructor(public title: string) {}
}

class DatedArticle extends TimeStamped(Article) {}

console.log(new DatedArticle('Mixins FTW').createdAt); // current date
Enter fullscreen mode Exit fullscreen mode

Authors’ note: “The class‑mixing factory keeps each concern isolated and plays well with static typing tools.”


3  Five Real‑World Use Cases

# Scenario Why a mixin fits
1 EventEmitter behaviour across services (Node.js, Deno)** Any class (e.g., Database, Cache, WebSocket) can emit/subscribe without inheriting from an EventEmitter base.
2 Timestamp & soft‑delete fields in ORMs (TypeORM, Sequelize)** CreatedAt, UpdatedAt, DeletedAt logic bolted onto otherwise unrelated models.
3 Vue.js global helpers (created(), methods) before Composition API Legacy apps share cross‑cutting features like $track() analytics with option–based mixins.
4 Shared animation controls in a React Native codebase A WithAnimated mixin injects startAnimation() / stopAnimation() into disparate screen classes without resorting to HOC wrappers.
5 Role‑based access checks in Express middleware objects Compose CanRead, CanWrite, CanDelete capabilities onto handler classes rather than deriving from a single bulky SecureController.

“Mixins thrive where behaviour is orthogonal to the main responsibility: logging, analytics, access control, lifecycle hooks.” – Learning Patterns


4  Trade‑offs & Best Practices

✅ Do ❌ Avoid
Keep mixins small and focused (1–2 related concerns). Mixing in stateful properties that can clash.
Document required interface contracts (this.id must exist, etc.). Relying on mixins for deep dependency chains (spaghetti).
Prefer functional class mixins to Object.assign for type‑safety. Mutating concrete instances at runtime (hard to debug).

The authors emphasise explicit composition. If two mixins rely on each other, wrap them in a higher‑order mixin rather than guessing load order.


5  When a Mixin Isn’t Enough

  • Hook / HOC – In React, prefer hooks (useFeature) or higher‑order components when the consumer is always a function component.
  • Trait / Interface – In TypeScript, interfaces document capability without implementation; sometimes that plus small helper functions is clearer.

“Mixin is a tool, not a religion. Reach for it when a pure function or a simple import won’t do.” – Learning Patterns


6  TL;DR Checklist

  • ✅ Need to add the same behaviour to multiple otherwise unrelated objects?
  • ✅ Behaviour doesn’t fit a clean is‑a inheritance?
  • ✅ Comfortable documenting the extra surface your mixin expects?

If all three, a mixin is likely the leanest path.


Further Reading

  • patterns.dev – full book (free, CC BY‑NC 4.0)
  • Addy Osmani & Lydia Hallie – talks on “Design Patterns for Modern JavaScript”
  • Mozilla MDN – Mixins

Content adapted from “Learning Patterns” (Patterns.dev) under Creative Commons BY‑NC 4.0.

Top comments (0)