type ClassConstructor<T> = new (...args:any[])=>T; //(1)
function withEZDebug<C extends ClassConstructor<{getDebugValue():object}>>(Class:C){
return class extends Class {
debug(){
let name = this.constructor.name;
let value =this.getDebugValue();
return `${name}(${JSON.stringify(value)})`
}
}
}
class HardToDebugUser{
constructor(
private id:number,
private firstName:string,
private lastName:string
){}
getDebugValue(){
return {
id:this.id,
name:this.firstName + ' ' + this.lastName
}
}
}
let User = withEZDebug(HardToDebugUser);
let user = new User(3,'Emmmmm','Gi');
console.log(user.debug()); // {id:..., name:...}
위 코드를 간단히 요약해보자.
(1): 모든 생성자를 표현하는 ClassConstructor 타입이다. 타입스크립트는 전적으로 구조를 기반으로 타입을 판단하므로 new로 생성할 수 있는 모든 것을 생성자로 규정한다. 인자는 어떤 타입의 매개변수가 올지 알 수 없으므로 임의의 개수의 any타입을 인수로 받는다.
withEZDebug는 class를 받아 debug라는 메소드를 추가한 확장된 클래스를 돌려준다. 이렇게 withEZDebug는 자신이 반환하는 class와 입력 받은 class를 mix 시켜 안에 주입한다 하여 mixin 기법이라 할 수 있고
보통 믹스인이라고 한다. 동작을 캡슐화하여 외부에서는 debug 함수의 정체를 모르게 할 수 있게된다.