본문으로 바로가기

www.notion.so/Decorators-ee9928ba4a0b4c5584ddaf478e3910ee

 

Decorators

Decorator 란 ?

www.notion.so

Mark Lee 님의 영상과 자료를 참고하였다.

 

 

<Class Decorator example 1>

 

데코레이터로 class에 메서드를 추가해줬는데 

TS에서 Property 'print' does not exist on type 'Test1'. 라며 타이핑 에러를 낸다.

어쩔 수 없이 as any 로 타입 단언을 해줘야 한다.

function classDecorator<T extends { new (...args: any[]): {} }>(constructorFn: T) {
  return class extends constructorFn { // 여기서 target은 decorator를 단 class를 의미함.
    constructor(...args: any[]) {
      super(args);
    }

    // print 라는 public 메서드를 추가해줌
    public print() {
      console.log('this is print');
    }
  };
}

@classDecorator
class Test1 {}

// 문제는 TS는 print라는 메서드가 있는지 모르기 때문에 type 단언으로 any 처리를 해줬음.
(new Test1() as any).print(); 

 

 

<Class Decorator example 2>

 

조금 더 복잡한 형태의 class decorator입니다.

function classDecoratorFactory(arg: string) {
  return function<T extends { new (...args: any[]): {} }>(constructorFn: T) {
  
    // print2 라는 메서드를 prototype에 설정
    constructorFn.prototype.print2 = function() {
      console.log('this is print2', arg);
    };
    
    // prototype에
    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

 

<Method Decorator example 1>

 

property Descriptor의 writable을 설정하여 값을 재할당할 수 있는지를 설정할 수 있습니다.

function methodDecoratorFactory(canBeEdit: boolean = false) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.writable = canBeEdit;
  };
}

class Test4 {
  @methodDecoratorFactory()
  first() {
    console.log("first original");
  }

  @methodDecoratorFactory(true)
  second() {
    console.log("second original");
  }

  @methodDecoratorFactory(false)
  third() {
    console.log("third original");
  }
}

const test4 = new Test4();

// runtime error
test4.first = function () {
  console.log("first new");
};

test4.second = function () {
  console.log("second new");
};

// runtime error
test4.third = function () {
  console.log("third new");
};

 

 

<Method Decorator example 2>

 

특정 조건에 따라 메서드에 조작을 가할 수 있습니다.

이거 정말... 좋군요

function log(show: boolean = true) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const original = descriptor.value; // original에 메서드를 담아두자

    descriptor.value = function (...args: any[]) {
      show && console.log("start"); // show가 true면 출력
      original(...args);
      show && console.log("end");
    };
  };
}

class Test5 {
  @log()
  print1(first: string, second: number) {
    console.log("print1", first, second);
  }

  @log(false)
  print2(first: string, second: number) {
    console.log("print2", first, second);
  }
}

const test5 = new Test5();

// start/end 출력 됨
test5.print1("mark", 36);

// start/end 출력 안 됨
test5.print2("mark", 36);

 

 

<Property Decorator 1>

 

사용 방법은 쉬운데, return 하는 내용이 Property Descriptor이다.

따라서, property의 속성을 제어할 수 있다. 여기서는 writable을 false로 만들어 readonly로 만들어 보겠다.

function propertyDecorator(target: any, propName: string): any {
  console.log(target);
  console.log(propName);
  return {
    writable: false
  };
}

class Test6 {
  @propertyDecorator
  name: string = 'Mark';
}

const test6 = new Test6();
test6.name = 'Anna'; // runtime error

 

 

<Property Decorator example 1 >

 

생략합니다. 일반적인 사용법이라.


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체