[Typescript] 13장 데코레이터

1. 명령줄(tsconfig.json 수정하기)

먼저 데코레이터를 사용하려면 tsconfig.json 파일에 experimentalDecorators 옵션을 활성화해줍니다.

{
  "compilerOptions": {
    "outDir": "./dist",
    "target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
    "module": "commonjs" /* Specify what module code is generated. */,
    "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
    "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
    "strict": true /* Enable all strict type-checking options. */,
    "skipLibCheck": true /* Skip type checking all .d.ts files. */,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["src/**/*"] // 컴파일 할 파일 경로
}

2. 데코레이터 팩토리 (Decorator Factories)

데코레이터 팩토리는 매개변수를 받는 데코레이터를 생성하는 함수로 아래와 같이 생성할 수 있습니다.

function Log(prefix: string) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    console.log(`${prefix} - ${propertyKey}`);
  };
}

3. 데코레이터 합성 (Decorator Composition)

여러 개의 데코레이터를 조합하여 사용할 수 있습니다.

function A() {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    console.log('A');
  };
}

function B() {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    console.log('B');
  };
}

class MyClass {
  @A()
  @B()
  myMethod() {
    console.log(`My Method`);
  }
}

const myClass = new MyClass();
myClass.myMethod();

4. 메서드 데코레이터

메서드 데코레이터는 클래스 메서드에 적용됩니다.

function LogMethod(
  target: any,
  propertyKey: string,
  descipritor: PropertyDescriptor
) {
  const originalMethod = descipritor.value;
  descipritor.value = function (...args: any[]) {
    console.log(`Method ${propertyKey} with`, args);
    return originalMethod.apply(this, args);
  };
}

class MyClass {
  @LogMethod
  myMethod(arg: number) {
    console.log(`MyMethod called with ${arg}`);
  }
}

const myClass = new MyClass();
myClass.myMethod(30);
/* Output
 Method myMethod with [ 30 ]
 MyMethod called with 30
*/

5. 접근자 데코레이터

접근자 데코레이터는 getter와 setter에 적용됩니다.

function LogAccessor(
  target: any,
  propertyKey: string,
  descipritor: PropertyDescriptor
) {
  const originalGet = descipritor.get;

  descipritor.get = function (this: any) {
    console.log(`Getter ${propertyKey} with`);
    return originalGet?.call(this); // optional chaining
  };
}

class MyClass {
  private _value: number = 0;

  @LogAccessor
  get value() {
    return this._value;
  }
}

const myClass = new MyClass();
console.log(myClass.value);
// Output: Getter value with : 0

6. 프로퍼티 데코레이터

프로퍼티 데코레이터는 클래스의 속성에 적용됩니다.

function LogProperty(target: any, propertyKey: string) {
  let value = target[propertyKey];

  const getter = () => {
    console.log(`Getter ${propertyKey} with: ${value}`);
    return value;
  };

  const setter = (newValue: any) => {
    console.log(`Setting ${propertyKey} to ${newValue}`);
    value = newValue;
  };

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

class MyClass {
  @LogProperty
  myProp: string = 'Initial Value';
}

const myClass = new MyClass();
console.log(myClass.myProp); // Output: Getter myProp: Initial Value
myClass.myProp = 'New Value'; // Output: Setting myProp to New value

7. 매개변수 데코레이터

매개변수 데코레이터는 메서드의 매개변수에 적용됩니다.

function LogParameter(
  target: any,
  propertyKey: string,
  parameterIndex: number
) {
  console.log(`Parameter in ${propertyKey} at position ${parameterIndex}`);
}

class MyClass {
  myMethod(@LogParameter param: string) {
    console.log(`Parameter value: ${param}`);
  }
}

const myClass = new MyClass();
myClass.myMethod('Hello');
// Output: Parameter in myMethod at position 0
// Parameter value: Hello

8. 메타데이터 

npm install reflect-metadata
import 'reflect-metadata';

function MyMetadata(key: string) {
  return function (target: any, propertyKey: string) {
    Reflect.defineMetadata(
      key,
      `metadata for ${propertyKey}`,
      target,
      propertyKey
    );
  };
}
class MyClass {
  @MyMetadata('key1')
  myMethod() {}
}

const metadataValue = Reflect.getMetadata(
  'key1',
  MyClass.prototype,
  'myMethod'
);

console.log(metadataValue);

 

 

GitHub - Koras02/typescript-bloging

Contribute to Koras02/typescript-bloging development by creating an account on GitHub.

github.com

 

LIST