studye / typescript

타입스크립트는 자바스크립트랑 다른 언어인가요?
7 stars 0 forks source link

[typescript - 2.2] Mix-in classes #37

Open kennyd98 opened 7 years ago

kennyd98 commented 7 years ago

Mix-in 이란?

예시 1

function Timestamped(Base: TBase) { return class extends Base { timestamp = Date.now(); }; }


* Mix-in 사용

class User { name: string;

constructor(name: string) {
    this.name = name;
}

}

// Create a new class by mixing "Timestamped" into "User" const TimestampedUser = Timestamped(User);

// Instantiate the new "TimestampedUser" class const user = new TimestampedUser("John Doe");

// We can now access properties from both the "User" class // and our "Timestamped" mixin in a type-safe manner console.log(user.name); console.log(user.timestamp);


### 예시 2 - 생성자를 갖는 Mix-in
* Mix-in 클래스의 확장자는 반드시 `...args: any[]` 형태의 파라미터를 정의함
* 범용적으로 적용할 수 있게 하기 위함 = 특정 파라미터 형태의 생성자를 갖는 클래스에 종속되지 않기 위함
```javascript
function Tagged<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        tag: string | null;

        constructor(...args: any[]) {
            super(...args);
            this.tag = null;
        }
    };
}

// Instantiate the new "TaggedUser" class const user = new TaggedUser("John Doe");

// We can now access properties from both the "User" class // and our "Tagged" mixin in a type-safe manner user.name = "Jane Doe"; user.tag = "janedoe";


### 예시 3 - 메소드를 갖는 Mix-in
```javascript
function Activatable<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        isActivated = false;

        activate() {
            this.isActivated = true;
        }

        deactivate() {
            this.isActivated = false;
        }
    };
}
const ActivatableUser = Activatable(User);

// Instantiate the new "ActivatableUser" class
const user = new ActivatableUser("John Doe");

// Initially, the "isActivated" property is false
console.log(user.isActivated);

// Activate the user
user.activate();

// Now, "isActivated" is true
console.log(user.isActivated);

예시 4 - 여러 Mix-in 동시에 사용하기

const SpecialUser = Activatable(Tagged(Timestamped(User)));
const user = new SpecialUser("John Doe");
kennyd98 commented 7 years ago

ORIGINAL - typescript document 번역


Mix-in 이란?

Mix-in 지원

var randomizerMixin = Base => class extends Base { randomize() { } };

class Foo { } class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

* 참고
  - [MDN Mixin description](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins)
  - [Real Mixins with JavaScript Classes](http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/)

### Mix-in 생성자 타입
* `any[]` 타입의 single rest argument
* object-like 타입의 반환
* 예시, `X` 가 특정 object-like 타입인 경우 아래와 같은 게 Mix-in 생성자 타입
```javascript
constructor (...args: any[]) {
   return X;
} 

Mix-in 클래스

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

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

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

function Tagged<T extends Constructor<{}>>(Base: T) {
    return class extends Base {
        _tag: string;
        constructor(...args: any[]) {
            super(...args);
            this._tag = "";
        }
    }
}

const TaggedPoint = Tagged(Point);

let point = new TaggedPoint(10, 20);
point._tag = "hello";

class Customer extends Tagged(Person) {
    accountBalance: number;
}

let customer = new Customer("Joe");
customer._tag = "test";
customer.accountBalance = 0;
interface Point {
    x: number;
    y: number;
}

const WithLocation = <T extends Constructor<Point>>(Base: T) =>
    class extends Base {
        getLocation(): [number, number] {
            return [this.x, this.y];
        }
    }