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
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
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)