Skip to content

Instantly share code, notes, and snippets.

@bradennapier
Last active June 27, 2020 22:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bradennapier/728d7650cd4c19fd5829adcb77725ef9 to your computer and use it in GitHub Desktop.
Save bradennapier/728d7650cd4c19fd5829adcb77725ef9 to your computer and use it in GitHub Desktop.
Typescript Mixins Example
import type { MainClass } from './MainClass';
export abstract class AnotherClassComponent {
async anotherFn(
this: MainClass,
) {
// is fully aware of this.someFn and other parts but generally should try
// to be self contained
}
// this would fail due to the allowOverwrites property in applyMixins
// @ts-expect-error Mixin collision with property someFn on AnotherClassComponent
async someFn() {}
}
/* eslint-disable @typescript-eslint/no-explicit-any */
export default function applyMixins(
derivedConstructor: { [key: string]: any },
baseConstructors: Array<{ [key: string]: any }>,
allowOverwrites = false,
): void {
baseConstructors.forEach((baseConstructor) => {
Object.getOwnPropertyNames(baseConstructor.prototype).forEach((name) => {
if (name === 'constructor') {
return;
}
if (
!allowOverwrites &&
Object.hasOwnProperty.call(derivedConstructor.prototype, name)
) {
throw new Error(
`Mixin collision with property ${name} on ${baseConstructor.prototype.constructor.name}`,
);
}
Object.defineProperty(
derivedConstructor.prototype,
name,
Object.getOwnPropertyDescriptor(
baseConstructor.prototype,
name,
) as PropertyDescriptor & ThisType<any>,
);
});
});
}
import type { MainClass } from './MainClass';
export abstract class ClassComponent {
async someFn(
this: MainClass,
) {
// blah blah blah
}
}
import applyMixins from './applyMixins';
import { ClassComponent } from './ClassComponent';
import { AnotherClassComponent } from './AnotherClassComponent';
class MainClass {
constructor( {
// only has constructor and holds the core shared data / types that abstract classes all share
}
}
applyMixins(MainClass, [
ClassComponent,
AnotherClassComponent
]);
interface MainClass extends ClassComponent, AnotherClassComponent {}
export { MainClass }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment