[Angular] Decorator

2022. 1. 5. 00:15Angular/Information

Decorator

반복적으로 선행되어야 할 로직을 한줄로 쉽게 호출하는 방법이다.

이는 이미 Angular에 내포되어 있을 수도 있고, 개발자가 직접 구현을 할 수도 있다.
(JavaKotlin의 Annotation과 유사한 개념이다.)
@Decorator와 같이 앞에 @을 붙여서 호출하며 ClassFunctionParameterVariables 에 적용할 수 있다.
하지만, 이 Decorator가 어디에 붙느냐(ClassFunctionParameterVariables)에 따라서 사용할 수 있는 방법이 다르기에 개발자는 이를 유의해야한다.

Class Decorator

  • Class 명 상단에 작성한다.
  • 생성자(constructor)를 인수로 갖는다.
  • Class의 생성자, 함수에 접근할 수 있다.
    하지만, Class에 선언된 변수에는 접근이 불가하다.
  • 일반적으로는 Parameter가 없고 Decorator 명만 기재한다.
    → 경우에 따라 넣어도 무관하다.

DecoratorParameter를 넣어 Class의 변화를 외부에서 조정하고 싶다면 Factory를 하나 만들어주면 된다.

FactoryDecorator로 사용하고, 실제 사용될 로직에 대해서 호출 하면 된다.

말로 설명하기 어려우니 아래 코드를 보자.

@TestFactory(false)
export class Person {
  name: string;
  age: number;

  constructor(name?: string, age?: number) {
    this.name = name ?? '';
    this.age = age ?? 0;
  }
}

function getMockData(constructorFn: any) {
  return <any>class extends constructorFn{
    name = 'y0ngha';
    age = 23;
  }
}

function TestFactory(isSetTestData: boolean) {
  return isSetTestData ? getMockData : null;
}

TestFactory Decorator에 true 혹은 false의 값이 들어갔을 때의 변화 차이는 아래와 같다.

  • True : { name : 'y0ngha', age : 23 }
  • False : { name : '', age : 0 }

Function Decorator

  • 함수명 상단에 작성한다.
  • target, propName, description을 인수로 갖는다.
    - target : Classprototype이다. 클래스의 모든 함수(생성자 포함)에 접근 가능하다.
    - propName : FunctionKey 값이며, Decorator가 붙은 함수명이 string으로 들어온다.
    - description : 함수의 기능을 뜻한다. description의 메서드로는 writable, enumerable, configurable, value가 존재한다.
    -- description.writable : 수정 가능 여부, false일 경우 Parameter 수정이 불가하다.
    -- description.enumerable : 열거형인지에 대한 여부, false일 경우 Object.keys(); 로 값을 받아올 수 없다.
    -- description.configurable : 위 2개를 한번에 적용할 수 있다.
    -- description.value : 함수의 값이 들어온다. 함수형의 형태를 갖고 있다.
class Foo {
  constructor() {
    console.log('Created Foo!');
  }

  printFoo() {
    console.log('Foo');
  }

  @Editable(true)
  printFoooooo() {
    console.log('Foooooo');
  }

}

function Editable(isEditable: boolean) {
  return (target: any, propName: string, description: PropertyDescriptor) => {
    description.writable = isEditable;
  }
}

Parameter Decorator

  • Parameter 좌측에 작성한다.
  • target, methodName, paramIndex를 인수로 갖는다.
    target : Class의 prototype이다. 클래스의 모든 함수(생성자 포함)에 접근 가능하다.
    - methodName : Decorator가 작성된 Parameter를 포함한 Function의 Key 값이며, Decorator가 붙은 Parameter의 함수명이 string으로 들어온다.
    - paramIndex : 몇번째 Parameter인지 알려준다.
function PrintInfo(target: any, methodName: string, paramIndex: number) {
  console.log('target', target);
  console.log('methodName', methodName);
  console.log('paramIndex', paramIndex);
}

class Person {
  private name: string;
  private age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  say(@PrintInfo message: string) {
    console.log(message);
  }
}

물론 이 Decorator는 생성자의 Parameter에도 걸 수 있다.

 

위 코드를 보면 다른 Decorator와 달리 Parameter Decorator는 리턴 값이 없는 것을 볼 수 있다.

이를 활용하기 위해서는 “reflect-metadata”에 명시적으로 접근해야 한다.
이를 통해 Parameter의 값을 수정할 수 있다.

만일 “refrect-metadata”를 import하고자 한다면, tsconfig.json의 옵션에서 emitDecoratorMetadata 를 추가하여야 한다.

Variable Decorator

  • 변수명 상단에 작성한다.
  • target, propName을 인수로 갖는다.
    target : Class의 prototype이다. 클래스의 모든 함수(생성자 포함)에 접근 가능하다.
    - propName : Decorator가 작성된 변수의 Key 값이며, Decorator가 붙은 변수명이 string으로 들어온다.
  • Variable Decorator는 리턴값으로 Function Decorator의 description과 같은 PropertyDescriptor 형을 리턴할 수 있다.
function Writable(isWritable: boolean) {
  return function(target:any, propName: string): any {
    return {
      writable: isWritable
    }
  }
}

class Person {
  @Writable(true)
  name: string = 'y0ngha';
}