본문 바로가기
Web/JavaScript

[TypeScript] Mixins

by llHoYall 2021. 7. 9.

Mixin is a way that building up classes by combining simpler partial classes.

It is a kind of component reuse.

Basics

It relies on using Generic with class Inheritance to extend a base class.

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

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

function MixinGenerator<T extends Constructor>(Base: T) {
  return class Example extends Base {
    _age = 1;

    setAge(age: number) {
      this._age = age;
    }

    get age(): number {
      return this._age;
    }
  };
}

const MixinClass = MixinGenerator(ExClass);

const mixin = new MixinClass("HoYa");
mixin.setAge(18);
console.log(`Hi, I'm ${mixin.name}. I'm ${mixin.age} years old.`);
// "Hi, I'm HoYa. I'm 18 years old."

In this example, we make a class using mixin.

In other words, we make a mixin class by extending a base class and returning it from the factory function.

Constrained Mixin

Mixin doesn't know about the base class, so it is hard to design a class that we want.

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

class ExClass {
  constructor(public x: number, public y: number) { }

  setCoordinate(x: number, y: number) {
    this.x = x;
    this.y = y;
  }

  say() {
    console.log(`X: ${this.x}, Y: ${this.y}`);
  }
}

type MixinType1 = GenericConstructor<ExClass>;
type MixinType2 = GenericConstructor<{ setCoordinate: (x: number, y: number) => void }>;
type MixinType3 = GenericConstructor<{ say: () => void }>;

function MixinGenerator1<T extends MixinType1>(Base: T) {
  return class MixinGenerator1 extends Base {
    constructor(...args: any[]) {
      super(args[0], args.slice(1));
    }
  };
}

function MixinGenerator2<T extends MixinType2>(Base: T) {
  return class MixinGenerator2 extends Base {
    setPoint() {
      this.setCoordinate(5, 7);
    }
  };
}

function MixinGenerator3<T extends MixinType3>(Base: T) {
  return class MixinGenerator3 extends Base {
    say = () => {
      console.log("Hello Mixin");
    }
  };
}

const MixinClass1 = MixinGenerator1(ExClass);
const MixinClass2 = MixinGenerator2(ExClass);
const MixinClass3 = MixinGenerator3(ExClass);

const mixin1 = new MixinClass1(1, 3);
const mixin2 = new MixinClass2(1, 3);
const mixin3 = new MixinClass3(1, 3);

mixin1.say(); // X: 1, Y: 3

mixin2.setPoint();
mixin2.say(); // X: 5, Y: 7

mixin3.say(); // Hello Mixin

In the above example, it allows for creating classes that only work with the constrained base class.

Then we can create mixins that only work when we have a particular base to build on.

'Web > JavaScript' 카테고리의 다른 글

[Svelte] Lifecycle  (0) 2021.11.12
[TypeScript] Indexed Access Types, Mapped Types, Conditional Types  (0) 2021.07.09
[TypeScript] Generic  (0) 2021.07.05
[TypeScript] Singleton Pattern  (0) 2021.07.05
[TypeScript] Class  (0) 2021.07.04

댓글