기본 구조

// Basic
function classDecorator<T extends { new (...args: any[]): {} }>(constructorFn: T) {...}

function classDecoratorFactory(...) {
	return function<T extends { new (...args: any[]): {} }>(constructorFn: T) {...}
}

@classDecorator
class Test {
}

@classDecorator()
class Test {
}

constructorFn

Class Decorator Example1

2woongjae/ts-basic-decorators

function classDecorator<T extends { new (...args: any[]): {} }>(target: T) {
  return class extends target {
    constructor(...args: any[]) {
      super(args);
    }

    public print() {
      console.log('this is print');
    }
  };
}

@classDecorator
class Test1 {}

(new Test1() as any).print();

Class Decorator Example2

2woongjae/ts-basic-decorators

function classDecoratorFactory(arg: string) {
  return function<T extends { new (...args: any[]): {} }>(constructorFn: T) {
    constructorFn.prototype.print2 = function() {
      console.log('this is print2', arg);
    };
    constructorFn.prototype.gender = 'male';
    return class extends constructorFn {
      public name = 'mark';
      private _age = 36;

      constructor(...args: any[]) {
        super(args);
      }

      public print() {
        console.log('this is print', arg);
      }
    };
  };
}

@classDecoratorFactory('what')
class Test2 {}

const test2 = new Test2();
(test2 as any).print(); // this is print what
(test2 as any).print2(); // this is print2 what
console.log(Test2.prototype); // class_1 { constructor: [Function: class_1], print: [Function] }
console.log(test2); // class_1 { name: 'mark', _age: 36 }
console.log(Object.keys(test2)); // [ 'name', '_age' ]
console.log((test2 as any).gender); // male