0
# Core Mixing
1
2
Core mixin functionality for creating classes that inherit from multiple base classes. The Mixin function is the primary way to combine multiple classes into a single class.
3
4
## Capabilities
5
6
### Mixin Function
7
8
Creates a new class that inherits properties and methods from multiple base classes.
9
10
```typescript { .api }
11
/**
12
* Creates a new class by mixing multiple classes together
13
* Supports up to 10 classes with full type inference
14
*/
15
function Mixin<A extends any[], I1, S1>(
16
c1: Class<A, I1, S1>
17
): Class<A, I1, S1>;
18
19
function Mixin<
20
A1 extends any[], I1, S1,
21
A2 extends any[], I2, S2
22
>(
23
c1: Class<A1, I1, S1>,
24
c2: Class<A2, I2, S2>
25
): Class<Longest<A1, A2>, I1 & I2, S1 & S2>;
26
27
function Mixin<
28
A1 extends any[], I1, S1,
29
A2 extends any[], I2, S2,
30
A3 extends any[], I3, S3
31
>(
32
c1: Class<A1, I1, S1>,
33
c2: Class<A2, I2, S2>,
34
c3: Class<A3, I3, S3>
35
): Class<Longest<A1, A2, A3>, I1 & I2 & I3, S1 & S2 & S3>;
36
37
function Mixin<
38
A1 extends any[], I1, S1,
39
A2 extends any[], I2, S2,
40
A3 extends any[], I3, S3,
41
A4 extends any[], I4, S4
42
>(
43
c1: Class<A1, I1, S1>,
44
c2: Class<A2, I2, S2>,
45
c3: Class<A3, I3, S3>,
46
c4: Class<A4, I4, S4>
47
): Class<Longest<A1, A2, A3, A4>, I1 & I2 & I3 & I4, S1 & S2 & S3 & S4>;
48
49
function Mixin<
50
A1 extends any[], I1, S1,
51
A2 extends any[], I2, S2,
52
A3 extends any[], I3, S3,
53
A4 extends any[], I4, S4,
54
A5 extends any[], I5, S5
55
>(
56
c1: Class<A1, I1, S1>,
57
c2: Class<A2, I2, S2>,
58
c3: Class<A3, I3, S3>,
59
c4: Class<A4, I4, S4>,
60
c5: Class<A5, I5, S5>
61
): Class<Longest<A1, A2, A3, A4, A5>, I1 & I2 & I3 & I4 & I5, S1 & S2 & S3 & S4 & S5>;
62
63
function Mixin<
64
A1 extends any[], I1, S1,
65
A2 extends any[], I2, S2,
66
A3 extends any[], I3, S3,
67
A4 extends any[], I4, S4,
68
A5 extends any[], I5, S5,
69
A6 extends any[], I6, S6
70
>(
71
c1: Class<A1, I1, S1>,
72
c2: Class<A2, I2, S2>,
73
c3: Class<A3, I3, S3>,
74
c4: Class<A4, I4, S4>,
75
c5: Class<A5, I5, S5>,
76
c6: Class<A6, I6, S6>
77
): Class<Longest<A1, A2, A3, A4, A5, A6>, I1 & I2 & I3 & I4 & I5 & I6, S1 & S2 & S3 & S4 & S5 & S6>;
78
79
function Mixin<
80
A1 extends any[], I1, S1,
81
A2 extends any[], I2, S2,
82
A3 extends any[], I3, S3,
83
A4 extends any[], I4, S4,
84
A5 extends any[], I5, S5,
85
A6 extends any[], I6, S6,
86
A7 extends any[], I7, S7
87
>(
88
c1: Class<A1, I1, S1>,
89
c2: Class<A2, I2, S2>,
90
c3: Class<A3, I3, S3>,
91
c4: Class<A4, I4, S4>,
92
c5: Class<A5, I5, S5>,
93
c6: Class<A6, I6, S6>,
94
c7: Class<A7, I7, S7>
95
): Class<Longest<A1, A2, A3, A4, A5, A6, A7>, I1 & I2 & I3 & I4 & I5 & I6 & I7, S1 & S2 & S3 & S4 & S5 & S6 & S7>;
96
97
function Mixin<
98
A1 extends any[], I1, S1,
99
A2 extends any[], I2, S2,
100
A3 extends any[], I3, S3,
101
A4 extends any[], I4, S4,
102
A5 extends any[], I5, S5,
103
A6 extends any[], I6, S6,
104
A7 extends any[], I7, S7,
105
A8 extends any[], I8, S8
106
>(
107
c1: Class<A1, I1, S1>,
108
c2: Class<A2, I2, S2>,
109
c3: Class<A3, I3, S3>,
110
c4: Class<A4, I4, S4>,
111
c5: Class<A5, I5, S5>,
112
c6: Class<A6, I6, S6>,
113
c7: Class<A7, I7, S7>,
114
c8: Class<A8, I8, S8>
115
): Class<Longest<A1, A2, A3, A4, A5, A6, A7, A8>, I1 & I2 & I3 & I4 & I5 & I6 & I7 & I8, S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8>;
116
117
function Mixin<
118
A1 extends any[], I1, S1,
119
A2 extends any[], I2, S2,
120
A3 extends any[], I3, S3,
121
A4 extends any[], I4, S4,
122
A5 extends any[], I5, S5,
123
A6 extends any[], I6, S6,
124
A7 extends any[], I7, S7,
125
A8 extends any[], I8, S8,
126
A9 extends any[], I9, S9
127
>(
128
c1: Class<A1, I1, S1>,
129
c2: Class<A2, I2, S2>,
130
c3: Class<A3, I3, S3>,
131
c4: Class<A4, I4, S4>,
132
c5: Class<A5, I5, S5>,
133
c6: Class<A6, I6, S6>,
134
c7: Class<A7, I7, S7>,
135
c8: Class<A8, I8, S8>,
136
c9: Class<A9, I9, S9>
137
): Class<Longest<A1, A2, A3, A4, A5, A6, A7, A8, A9>, I1 & I2 & I3 & I4 & I5 & I6 & I7 & I8 & I9, S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 & S9>;
138
139
function Mixin<
140
A1 extends any[], I1, S1,
141
A2 extends any[], I2, S2,
142
A3 extends any[], I3, S3,
143
A4 extends any[], I4, S4,
144
A5 extends any[], I5, S5,
145
A6 extends any[], I6, S6,
146
A7 extends any[], I7, S7,
147
A8 extends any[], I8, S8,
148
A9 extends any[], I9, S9,
149
A10 extends any[], I10, S10
150
>(
151
c1: Class<A1, I1, S1>,
152
c2: Class<A2, I2, S2>,
153
c3: Class<A3, I3, S3>,
154
c4: Class<A4, I4, S4>,
155
c5: Class<A5, I5, S5>,
156
c6: Class<A6, I6, S6>,
157
c7: Class<A7, I7, S7>,
158
c8: Class<A8, I8, S8>,
159
c9: Class<A9, I9, S9>,
160
c10: Class<A10, I10, S10>
161
): Class<Longest<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>, I1 & I2 & I3 & I4 & I5 & I6 & I7 & I8 & I9 & I10, S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 & S9 & S10>;
162
```
163
164
**Usage Examples:**
165
166
```typescript
167
import { Mixin } from "ts-mixer";
168
169
// Basic mixin with two classes
170
class Disposable {
171
isDisposed: boolean = false;
172
dispose() {
173
this.isDisposed = true;
174
}
175
}
176
177
class Activatable {
178
isActive: boolean = false;
179
activate() {
180
this.isActive = true;
181
}
182
deactivate() {
183
this.isActive = false;
184
}
185
}
186
187
class SmartObject extends Mixin(Disposable, Activatable) {
188
interact() {
189
this.activate();
190
console.log("Interacting with active object");
191
}
192
}
193
194
const obj = new SmartObject();
195
obj.activate();
196
obj.dispose();
197
console.log(obj.isActive, obj.isDisposed); // true, true
198
199
// Mixing classes that extend other classes
200
class Animal {
201
name: string;
202
constructor(name: string) {
203
this.name = name;
204
}
205
}
206
207
class Mammal extends Animal {
208
warmBlooded: boolean = true;
209
}
210
211
class Flyable {
212
fly() {
213
return "Flying!";
214
}
215
}
216
217
class Bat extends Mixin(Mammal, Flyable) {
218
constructor(name: string) {
219
super(name);
220
}
221
222
hunt() {
223
return `${this.name} is ${this.fly().toLowerCase()} and hunting`;
224
}
225
}
226
227
const bat = new Bat("Vampire Bat");
228
console.log(bat.hunt()); // "Vampire Bat is flying! and hunting"
229
console.log(bat.warmBlooded); // true
230
231
// Mixing abstract classes (requires TypeScript 4.2+)
232
abstract class Shape {
233
abstract getArea(): number;
234
}
235
236
abstract class Named {
237
abstract getName(): string;
238
}
239
240
class Circle extends Mixin(Shape, Named) {
241
constructor(private radius: number, private name: string) {
242
super();
243
}
244
245
getArea(): number {
246
return Math.PI * this.radius * this.radius;
247
}
248
249
getName(): string {
250
return this.name;
251
}
252
}
253
254
const circle = new Circle(5, "My Circle");
255
console.log(`${circle.getName()}: ${circle.getArea()}`);
256
```
257
258
## Mixin Behavior
259
260
### Constructor Handling
261
262
When mixing classes, ts-mixer creates instances of each base class and copies their properties to the mixed instance. This means:
263
264
- Each base class constructor is called with the same arguments
265
- Constructor side effects involving `this` may not work as expected
266
- Use init functions (configured via `settings.initFunction`) for `this`-dependent side effects
267
268
### Property Copying
269
270
- Instance properties from all base classes are copied to the mixed instance
271
- Static properties are handled according to `settings.staticsStrategy`
272
- Getters and setters are properly preserved
273
- Protected and private properties are supported
274
275
### Method Resolution
276
277
- When multiple classes define the same method, the last class in the mixin list takes precedence
278
- Method resolution follows the prototype chain of the mixed class
279
- Override precedence can be controlled by the order of classes in the mixin call
280
281
### Static Property Inheritance
282
283
Static properties and methods from all base classes are inherited by the mixed class, subject to the configured strategy:
284
285
- `'copy'` strategy: Static properties are copied at mixin creation time
286
- `'proxy'` strategy: Static property access is proxied to base classes
287
288
## Error Handling
289
290
The Mixin function will throw errors in the following scenarios:
291
292
- Invalid arguments (non-constructor functions)
293
- Circular mixin dependencies
294
- Memory-related issues with very deep prototype chains
295
296
When using proxy strategies, additional errors may be thrown:
297
- Cannot set prototype of proxies created by ts-mixer
298
- Cannot define new properties on proxies created by ts-mixer
299
- Cannot delete properties on proxies created by ts-mixer