[TypeScript] Decorator란?

LMH·2023년 4월 5일
0
post-thumbnail

Decorator란?

TypeScript 데코레이터(Decorators)는 클래스, 메소드, 프로퍼티 등의 선언 앞에 @ 기호를 사용하여 붙여지며, 이를 통해 런타임에서 클래스나 메소드 등을 변경하는 기능을 제공합니다.

데코레이터를 사용하기 위해서는 ts.config 파일에서 target을 "es6"로 experimentalDecorator을 "true"로 설정해야 사용할 수 있습니다.

데코레이터를 사용하면 코드를 더욱 간결하게 작성할 수 있으며, 재사용성을 높일 수 있습니다. 일반적으로 데코레이터는 클래스나 메소드에 추가적인 기능을 부여하기 위해 사용됩니다.

데코레이터를 작성하는 방법은 함수를 정의하는 것과 비슷합니다. 데코레이터 함수는 대상 클래스 또는 메소드를 매개변수로 받으며, 추가적인 동작을 수행한 후 수정된 클래스 또는 메소드를 반환합니다.

Class Decorator

function withTimestamp<T extends { new(...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    timestamp = new Date();

    logTimestamp() {
      console.log(`Created at ${this.timestamp}`);
    }
  };
}

@withTimestamp
class MyClass {
  constructor(public name: string) {}
}

const myInstance = new MyClass("John");
console.log(myInstance.name); // "John"
myInstance.logTimestamp(); // "Created at <current date>"

위의 코드는 withTimestamp Class 데코레이터를 정의하고, MyClass 클래스에 @withTimestamp 데코레이터를 적용합니다. @withTimestamp 데코레이터는 MyClass 클래스에 timestamp 프로퍼티와 logTimestamp 메소드를 추가합니다.

withTimestamp 함수는 기존 클래스를 확장하여 새로운 클래스를 반환합니다. 반환된 클래스는 timestamp 프로퍼티를 추가하고, logTimestamp 메소드를 구현합니다.

위의 코드에서 myInstance 객체를 생성한 후 name 프로퍼티를 출력하면 John이 출력됩니다. logTimestamp 메소드를 호출하면 Created at current date가 출력됩니다. 이는 withTimestamp 데코레이터가 MyClass 클래스를 수정하여 timestamp 프로퍼티와 logTimestamp 메소드를 추가했기 때문입니다.

Method Decorator

function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Method ${propertyKey} called with args ${JSON.stringify(args)}`);
    const result = originalMethod.apply(this, args);
    console.log(`Method ${propertyKey} returned ${JSON.stringify(result)}`);
    return result;
  };

  return descriptor;
}

class MyClass {
  @log
  myMethod(arg1: string, arg2: number) {
    return `Hello, ${arg1} (${arg2})`;
  }
}

const myInstance = new MyClass();
myInstance.myMethod("world", 123);

위의 코드는 log 데코레이터를 정의하고, MyClass 클래스의 myMethod 메소드에 @log 데코레이터를 적용합니다. @log 데코레이터는 myMethod가 호출될 때마다 콘솔에 로그를 출력하도록 수정됩니다.

데코레이터를 사용하면 코드를 더욱 간결하고 읽기 쉽게 작성할 수 있으며, 클래스나 메소드에 추가적인 기능을 부여할 수 있습니다. 하지만 데코레이터를 남발하면 코드를 복잡하게 만들 수 있으므로, 적절한 사용을 권장합니다.

Property Decorator

Copy code
function uppercase(target: any, key: string) {
  let value = target[key];

  const getter = function() {
    return value;
  };

  const setter = function(newVal: string) {
    value = newVal.toUpperCase();
  };

  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true
  });
}

class MyClass {
  @uppercase
  greeting: string;

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

const myInstance = new MyClass("Hello, World!");
console.log(myInstance.greeting); // "HELLO, WORLD!"

위의 코드는 uppercase Property 데코레이터를 정의하고, MyClass 클래스의 greeting 프로퍼티에 @uppercase 데코레이터를 적용합니다. @uppercase 데코레이터는 greeting 프로퍼티 값을 대문자로 변경합니다.

Object.defineProperty 메소드를 사용하여 greeting 프로퍼티의 getter와 setter를 수정합니다. getter는 원래의 값을 그대로 반환하고, setter는 대문자로 변경한 값을 저장합니다.

위의 코드에서 myInstance.greeting을 호출하면 HELLO, WORLD!가 출력됩니다. 이는 Property 데코레이터가 greeting 프로퍼티 값을 대문자로 변경했기 때문입니다.

Parameter Decorator

function logParameter(target: any, key: string, index: number) {
  const originalMethod = target[key];
  target[key] = function(...args: any[]) {
    console.log(`Function ${key} called with parameter ${index}: ${args[index]}`);
    return originalMethod.apply(this, args);
  };
}

class MyClass {
  constructor(public name: string) {}

  @logParameter
  greet(@logParameter msg: string) {
    console.log(`${this.name} says ${msg}`);
  }
}

const myInstance = new MyClass("John");
myInstance.greet("Hello, World!"); // "Function greet called with parameter 0: Hello, World!" "John says Hello, World!"

위의 코드는 logParameter Parameter 데코레이터를 정의하고, greet 메소드의 msg 매개변수에 @logParameter 데코레이터를 적용합니다. @logParameter 데코레이터는 greet 메소드가 호출될 때, 해당 매개변수 값을 로그에 출력합니다.

target[key] = function(...args: any[]) 코드는 메소드를 수정하여 새로운 함수를 생성합니다. 이 새로운 함수는 원래의 메소드를 호출하면서, 매개변수 값을 로그에 출력합니다.

위의 코드에서 myInstance.greet("Hello, World!")를 호출하면, Function greet called with parameter 0: Hello, World!와 John says Hello, World!가 출력됩니다. 이는 Parameter 데코레이터가 greet 메소드의 msg 매개변수 값을 로그에 출력했기 때문입니다.

profile
새로운 것을 기록하고 복습하는 공간입니다.

0개의 댓글