TypeScript Decorator

SSAD·2023년 2월 18일
0

BackEnd

목록 보기
32/44
post-thumbnail
post-custom-banner

Deocorators

  • 현재 decorator는 class및 class 내부에서만 사용할 수 있음
  • 즉, decorator는 class, class 내부의 property, accessor, method parameter에 사용할 수 있음

decorator 특징

  • class의 다양한 property 및 method의 정의를 수정 및 교체하는 function
  • runtime에 호출(class instance를 생성하지 않아도 호출)

Decorators 기능 활성화

  1. tscofig.json 설정 추가
{
  "compilerOptions": {
    "target": "ES2017",
    "experimentalDecorators": true
  }
}

Example

데코레이터 첫 적용 해보기

function zzz(aaaaaa) {
  console.log("==============");
  console.log(aaaaaa);
  console.log("==============");
}

@zzz
class AppController {}

결과


class decorator

class decorator는 클래스의 생성자를 유일한 인수로 호출

  • 클래스 선언에 사용되는 클래스 데코레이터는 기존의 클래스 정의를 확장하는 용도로 사용할 수 있음
  • 클래스 데코레이터 함수의 인자로는 클래스(생성자 함수)가 전달
  • 클래스 데코레이터 함수에서는 새로운 클래스(생성자 함수)만 반환할 수 있음
  • 외의 값은 무시됨
@ClassDecorator
class A {
  b: string = "Hello"

  get c(): string {
    return `${this.b} World!`
  }

  d(e: string): void {
    console.log(e)
  }
}

function ClassDecorator(constructor: typeof A) {
  console.log(constructor)
  console.log(constructor.prototype)
}

결과

@ClassDecorator
class A {
  b: string = "Hello";

  get c(): string {
    return `${this.b} World!`;
  }

  d(e: string): void {
    console.log(e);
  }
}

function ClassDecorator(constructor: typeof A) {
  const method = constructor.prototype.d; // 기존의 method
  // 기존의 method를 재정의 한다.
  constructor.prototype.d = function (e: string) {
    method(e); // 기존의 method를 호출하고, 아래를 추가한다.
    console.log("d()를 호출하면 이것도 호출된다!");
  };
}

new A().d("안녕!");

결과

  • ClassDecorator를 통해 class 내부의 method뿐만 아니라
    접근 가능한 constructor, accessor, 그리고 method 모두를 핸들링 할수 있음

method decorator

method decorator는 3가지 argument를 받음

  • 1 : class의 prototype
  • 2 : class에서 해당 method의 key
  • 3 : property descriptor
const obj = {};
console.log(typeof obj); // object
// console.log(obj.prototype); // error

const func = function () {};
console.log(func.prototype); // ok

console.log(typeof Object); // function
console.log(Object.prototype); // ok

class A {}
console.log(typeof A); // function
console.log(A.prototype); // ok
  • prototype은 function만 가지는 property
  • js,ts에서 class는 function임

method에서 property descriptor

  • Property : Description
    • value : 현재 값 value
    • writable : 수정가능하면 true, 아니면 false
    • enumarable: for(i in [1,2,3)]과 같이 순회가 가능하면 true, 아니면 false
    • configurable: Property definition이 수정 및 삭제가 가능하면 true, 아니면 false
class A {
  b: string = "Hello";

  get c(): string {
    return `${this.b} World!`;
  }

  @LogError
  d(e: string): void {
    console.log(e);
  }
}

function LogError(target: any, key: string, desc: PropertyDescriptor): void {
  console.log("target", target);
  console.log("key", key);
  console.log("desc", desc);
}

결과

데코레이터 실제 호출한 것

LogError(A.prototype, "d", Object.getOwnPropertyDescriptor(A.prototype, "d")!)
class A {
  b: string = "Hello"

  get c(): string {
    return `${this.b} World!`
  }

  @LogError
  d(e: string): void {
    console.log(e)
    throw new Error()
  }
}

function LogError(target: any, key: string, desc: PropertyDescriptor): void {
  const method = desc.value

  desc.value = function (e: string) {
    try {
      method(e)
    } catch (err) {
      console.log("여기에 error handling logic 추가하면 됨!")
    }
  }
}

new A().d("안녕!")

결과

class A {
  b: string = "Hello"

  get c(): string {
    return `${this.b} World!`
  }

  @LogError("ㅎㅎㅎ")
  d(e: string): void {
    console.log(e)
    throw new Error()
  }
}

function LogError(errorMessage: string) {
  return function (target: any, key: string, desc: PropertyDescriptor): void {
    const method = desc.value

    desc.value = function (e: string) {
      try {
        method(e)
      } catch (err) {
        console.log(errorMessage)
      }
    }
  }
}

new A().d("안녕!")

결과


parameter decorator

parameter decoratoreh 3가지 argument를 받음

  • 1 : class의 prototype
  • 2 : class에서 해당 method의 key
  • 3 : 해당 parameter의 index 번호
class A {
  b: string = "Hello";

  get c(): string {
    return `${this.b} World!`;
  }

  d(
    @ParameterDecorator e: string,
    @ParameterDecorator f: string,
    @ParameterDecorator g: string
  ): void {
    console.log(e, f, g);
  }
}

function ParameterDecorator(target: any, key: string, index: number) {
  console.log("target", target);
  console.log("key", key);
  console.log("index", index);
}

결과


profile
learn !
post-custom-banner

0개의 댓글