320x100
320x100

데코레이터

: 데코레이터 함수를 뜻하며, 코드에 첨부하여 메서드 및 함수에 추가적인 기능을 더하는 선언

: 비슷한 개념으로 자바의 어노테이션이 있는데, 타입스크립트에서는 파이썬의 데코레이터와 비슷한 개념이다

 

- 타입스크립트에서의 데코레이터

: 클래스 선언, 메서드, 접근자, 프로퍼티, 매개변수에 첨부할 수 있는 특수한 선언

: 파이썬과 동일하게 런타임에 실행되며, 메서드나 클래스 인스턴스가 만들어질때 실행된다

: 데코레이터는 클래스 또는 클래스 내부의 생성자, 프로퍼티, 접근자, 메서드, 매개변수에만 장식될 수 있다

 

 

 

 

타입스크립트와 데코레이터

: 타입스크립트와 ES6에 클래스가 도입됨에 따라 클래스 및 클래스 멤버에 어노테이션을 달거나 수정하기 위한 기능으로 제공

: 현재는 타입스크립트의 실험적인 기능으로 이용가능하며, 향후 릴리즈에서 변경이 될 수 있다

 

- 데코레이터 기능 활성화

: tsconfig.json 수정

{
    "compilerOptions": {
        "target": "ES6",
        "experimentalDecorators": true
    }
}

 

 

 

 

 

 

데코레이터 팩토리 (Decorator Factory)

: 데코레이터 함수를 감싸는 래퍼 함수

: 보통 데코레이터가 선언에 적용되는 방식을 수정할때 사용

: 즉, 단순히 데코레이터가 런타임에 호출할 표현식을 반환하는 함수

 

- 데코레이터 함수

: 실질적인 데코레이터의  로직

: target (현재 타겟), key (속성 이름), descriptor (설명)이 파라미터로 전달되며, 어떤 멤버를 장식했느냐에 따라 인수가 달라질 수 있다

 

- 예시

function color(value: string) { // 데코레이터 팩토리
    return function (target) { // 데코레이터
        // 'target'과 'value' 변수를 가지고 무언가를 수행합니다.
    }
}

 

 

 

 

 

 

데코레이터 합성 (Decorator Composition)

: 데코레이터 선언 시 여러 데코레이터를 적용할 수 있다

: 여러 데코레이터가 단일 선언에 적용되는 경우 수학의 합성 함수와 비슷하게 적용됨

: 각 데코레이터의 표현은 위에서 아래로 평가되고, 결과는 아래에서 위로 함수로 호출됨

 

- 단일 행

@f @g x

 

- 여러 행

@f
@g
x

 

- 예시

function f() {
    console.log("f(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("f(): called");
    }
}

function g() {
    console.log("g(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("g(): called");
    }
}

class C {
    @f()
    @g()
    method() {}
}
// 결과
f(): evaluated
g(): evaluated
g(): called
f(): called

 

 

 

 

 

 

 

클래스 데코레이터

: 클래스 선언 직전에 선언되는 데코레이터

: 클래스 생성자에 적용되며 클래스 정의를 관찰, 수정 또는 교체하는데 사용

: 선언 파일이나 주변 컨텍스트 (ex) 선언 클래스)에서 사용할 수 없음

 

- 매개변수

: constructor (생성자 함수가 데코레이터로 자동 전달하므로 명시하지 않아도 됨)

 

- 반환 값

: class, void

 

- 예시

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

   // Test 클래스의 constructor를 상속해서 new Test() 가 되면 추가된 생성자도 실행되도록 설정
   return class extends constructor { 
      first_prop = 'override'; // 데코레이터에서 새로 프로퍼티를 덮어씌움
      new_prop = 'new property'; // 데코레이터에서 새로 프로퍼티를 추가
   };
}

@classDecorator
class Test {
   first_prop: string;

   constructor(m: string) {
      this.first_prop = m;
   }
}

let t = new Test('abcdefg');
console.log(t);

console.log( t.first_prop ); // 'override'

// 데코레이터로 설정된 프로토타입 확장은 타입 단언(Type Assertion) 필요
console.log( (t as any).new_prop ); 'new property'
[Running] ts-node "index.ts"
Test { 
    first_prop: 'override', 
    new_prop: 'new property' 
}
override
new property

: 생성자가 프로퍼티로 덮어씌워졌다

 

- 데코레이터 컨테이너 활용

// 데코레이터 컨테이너
function classDecorator(param1: string, param2: string) {
   // 데코레이터 함수
   return function <T extends { new (...args: any[]): {} }>(constructor: T) {
      return class extends constructor {
         new_prop = param1;
         first_prop = param2;
      };
   };
}

@classDecorator('안녕하세요', '반갑습니다')
class Test {
   first_prop: string;

   constructor(m: string) {
      this.first_prop = m;
   }
}

let t = new Test('world');
console.log(t);
[Running] ts-node "index.ts"
Test { 
    first_prop: '반갑습니다', 
    new_prop: '안녕하세요' 
}

: 데코레이터를 사용할때 파라미터를 전달해서 사용할 수 있다

 

 

 

 

 

 

 

메서드 데코레이터

: 메서드 선언 직전에 선언하는 데코레이터

: 메서드의 프로터티 설명자 (property descriptor)에 적용되며 메서드 정의를 관찰, 수정, 대체하는데 사용

: 선언 파일, 오버로드 또는 기타 주변 컨텍스트 (ex) 선언 클래스)에서 사용할 수 없음

 

- 매개변수

: static 프로퍼티라면 클래스의 생성자 함수, 인스턴스 프로퍼티면 클래스의 prototype 객체

: 해당 메서드의 이름

: 해당 메서드의 property descriptor

 

- descriptor 재정의

: 메서드 데코레이터는 호출된 메서드로 정의된 메서드 순으로 전달을 받는데, 해당 메서드가 호출될때 특정 로직을 동작시키고 싶으면 아래와 같이 descriptor를 재정의 할 수 있다

: value (현재 값의 value)

: writable (수정 가능하면 true)

: enumarable (순회가 가능하면 true)

: configurable (property definition이 수정 및 삭제가 가능하면 true)

 

- 예시

function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.enumerable = value;
    };
}

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }

    @enumerable(false)
    greet() {
        return "Hello, " + this.greeting;
    }
}

 

 

 

 

 

 

 

접근자 데코레이터

: 접근자 선언 바로 전에 선언

: 접근자의 프로퍼티 설명자에 적용되며 접근자의 정의를 관찰, 수정, 교체하는데 사용

: 선언 파일이나 주변 컨텍스트 (ex) 선언 클래스)에서 사용할 수 없음

 

- 예시

function configurable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.configurable = value;
    };
}

class Point {
    private _x: number;
    private _y: number;
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }

    @configurable(false)
    get x() { return this._x; }

    @configurable(false)
    get y() { return this._y; }
}

 

 

 

 

 

 

 

 

프로퍼티 데코레이터

: 프로퍼티 선언 바로 전에 선언되는 데코레이터

: 선언 파일이나 주변 컨텍스트 (ex) 선언 클래스)에서 사용할 수 없음

 

- 매개변수

: static 프로퍼티면 클래스의 생성자 함수, 인스턴스 프로퍼티라면 클래스의 property 객체

: 해당 property의 이름

 

- 반환 값

: Property Descriptor 형태

: void

 

- 예시

function writable(writable: boolean) {
   return function (target: any, decoratedPropertyName: any): any {
      return {
         writable,
      };
   };
}

class Test {
   property = 'property';

   @writable(false)
   public data1 = 0;

   @writable(true)
   public data2 = 0;
}

const t = new Test();
t.data1 = 1000;
t.data2 = 1000; // 런타임 에러 !! - data2는 writable이 false라서 값을 대입할 수가 없다.

 

 

 

 

 

 

매개변수 데코레이터

: 매개변수 선언 직전에 선언되는 데코레이터

: 클래스 생성자 또는 메서드 선언의 함수에 적용

: 선언 파일, 오버로드 또는 다른 주변 컨텍스트 (ex) 선언 클래스)에서 사용할 수 없다

 

- 매개변수

: static 프로퍼티라면 클래스의 생성자 함수, 인스턴스 프로퍼티라면 클래스의 prototype 객체

: 매개변수가 들어있는 method의 이름

: 메서드 파라미터 목록에서의 index

 

- 예시

function parameterDecorator(target: any, methodName: string, paramIndex: number) {
   console.log('parameterDecorator start');
   console.log(target);
   console.log(methodName);
   console.log(paramIndex);
   console.log('parameterDecorator end');
}

class Test7 {
   private _name: string;
   private _age: number;

   constructor(name: string, @parameterDecorator age: number) {
      this._name = name;
      this._age = age;
   }

   print(@parameterDecorator message: string) {
      console.log(message);
   }
}
[Running] ts-node "index.ts"
parameterDecorator start
Test7 { print: [Function] }
print
0
parameterDecorator end

parameterDecorator start
[Function: Test7]
undefined
1
parameterDecorator end

 

 

 

 

 

 

 

데코레이터의 호출순서

: 프로퍼티 > 메서드 > 파라미터 > 클래스

 

 

 

 

 

 

 

 

reference

 

TypeScript 한글 문서

TypeScript 한글 번역 문서입니다

typescript-kr.github.io

 

📘 타입스크립트 @데코레이터 개념 & 사용법

타입스크립트 Decorator 란 타입스크립트로 Angular.js 나 Nest.js 개발을 진행하다보면 필연적으로 데코레이터란 것을 접하게 된다. 자바(Java)를 해본 분들이라면 어노테이션과 비슷하다고 볼수 있지

inpa.tistory.com

 

 

300x250
728x90