타입스크립트 데코레이터 사용하기

임현규·2023년 1월 15일
0

타입스크립트 설정하기

아무 설정 없이 타입스크립트에서 데코레이터를 사용할 수 없다. 우선 tsconfig.json에서 해당 부분을 설정한다.

{
    "compilerOptions": {
        "experimentalDecorators": true  // 데코레이터를 지원을 위한 옵션
    },
    "exclude": ["node_modules"],
    "include": ["src/**/*"]
}

데코레이터란?

데코레이터 패턴을 떠올리면 되겠다. 기존 코드를 유지하고 거기에 모듈을 덧씌우는 작업이다. 이를 통해 기본 코드는 유지하고 기능을 추가할 수 있다.

자바로 따지면 다이나믹 프록시, 또는 annotation 구현 후 aop를 적용하는 것과 비슷하다고 보면 되겠다.

js에서 데코레이터는 타입 정의시 바로 호출한다. 그렇기에 aop처럼 활용하려면 몇가지 트릭이 필요하다.

데코레이터 적용

데코레이터는 크게 4가지 부분에 적용가능하다.

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

클래스 데코레이터

function Logger(logString: string) {
    return function (constructor: Function) {
        console.log(constructor.name + " " + logString);
    };
}

@Logger("Hello")
class Person {
    name: string = "max";

    constructor() {
        console.log("Creating person object");
    }
}

const per = new Person();

클래스 데코레이터는 constructor를 인자로 받아서 function함수를 생성한다. 이 때 처음 function을 정의한 Logger의 인자는 데코레이터에서 받을 인자이다.

클래스 데코레이터는 인스턴스 생성시 호출한다

proxy를 생성해보자

function Log(param1: string) {
    return function <T extends { new (...args: any[]): {} }>(constructor: T) {
        return class extends constructor {
            new_prop = param1;
        }
    }
}

해당 클래스를 상속받아서 기능을 확장한다.

속성 데코레이터

function Log(target: any, propertyName: string | Symbol) {
    console.log("Property decorator!");
    console.log(target, propertyName);
}

class Product {

    @Log
    title: string;
    private price: number;

    constructor(title:string, price:number) {
        this.title = title;
        this.price = price;
    }
}

속성 데코레이터는 인자로 target과 propertyName을 받는다. 리턴값을 propertyDescriptor로 줘서 속성을 설정할 수 있다.

function Constant() {
    return function (target: any, propertyName: any): any {
        return {
            writable: false
        };
    };
}

메서드 데코레이터

function Log2(target: any, name: string, descriptor: PropertyDescriptor) {
    console.log("method decorator!");
    console.log(target);
    console.log(name);
    console.log(descriptor);
}

메서드 데코레이터는 PropertyDescriptor의 수정으로 aop처럼 사용할 수 있다.
데코레이터는 타입 생성시 바로 호출되는데 이 때 descriptor 내부를 수정하면 aop처럼 활용할 수 있다.

PropertyDescriptor란 ES5에서 추가된 객체로 객체를 좀 더 세부적으로 정의할 수 있다. PropertyDescriptor가지는 속성은 다음과 같다.

{
value: [Function: hello],
writable: true,
enumerable: false,
configurable: true
}

value는 함수
writable은 수정 가능 여부
enumerable은 순회 여부
configurable은 property definition이 수정 및 삭제 가능한지 여부

핵심은 value로 자바에서 reflection Method와 비슷한역할이다. decriptor를 활용해 재정의 해보자

function TimeCheck(target: any, name: string, descriptor: PropertyDescriptor) {
    let method = descriptor.value;
    descriptor.value = function (...args: any) {
        console.log("before");
        const resultObject = method.apply(this, args);
        console.log("after");
        return resultObject;
    };
}

descriptor.value를 수정하면 데코레이터 패턴처럼 사용가능하다.

파라미터 데코레이터

function Log3(target: any, name: string | symbol, position: number) {
        console.log("Parameter decorator!");
        console.log(target);
        console.log(name);
        console.log(position);
}

파라미터 데코레이터는 target, name, position을 입력받는다.

참고

https://inpa.tistory.com/entry/TS-%F0%9F%93%98-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%EA%B0%9C%EB%85%90-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC#%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0_%ED%8C%A9%ED%86%A0%EB%A6%AC

profile
엘 프사이 콩그루

0개의 댓글