Decorators
- decorator로 지정할 함수 이름 앞에
@
기호를 붙여줌
- decorator는 class가 정의만 되도 실행됨 (class가 인스턴스화되기 전에 실행)
- decorator에는 인자를 가지고 있고, 이 인자는 decorator를 사용하는 위치에 따라 달라짐
- 인자를 사용하지 않을 경우,
-
를 써서 사용하지 않을 것을 명시해줌
function Logger(constructor: Function) {
console.log('Logging...');
console.log(constructor);
}
@Logger
class Person {
name = 'Max';
constructor() {
console.log('Creating Person object...');
}
}
const pers = new Person();
Decorator를 사용하기 위한 tsconfig 설정
target
속성이 es6
이상이어야 함
experimentalDecorators
속성이 true이어야 함
Decorator Factory
- decorator 함수를 반환하는 함수
- 장점 : 함수의 인자로 받은 값을 decorator에 전달해줄 수 있음
function Logger(logString: string) {
return function(constructor: Function) {
console.log(logString);
console.log(constructor);
}
}
@Logger('Login - Person')
class Person {
name = 'Max';
constructor() {
console.log('Creating Person object...');
}
}
const pers = new Person();
Decorator Factory Example
- decorator를 사용하여 DOM을 조작할 수 있음
function WithTemplate(template: string, hookId: string) {
return function(_: Function) {
const hookEl = document.getElementById(hookId);
if (hookEl) {
hookEl.innerHTML = template;
}
}
}
@WithTemplate('<h1>My Person Object</h1>', 'app')
class Person {
name = 'Max';
constructor() {
console.log('Creating Person object...');
}
}
const pers = new Person();
- class의 constrcutor에 접근할 수 있음
function WithTemplate(template: string, hookId: string) {
return function(constructor: any) {
const hookEl = document.getElementById(hookId);
const p = new constructor();
if (hookEl) {
hookEl.innerHTML = template;
hookEl.querySelector('h1')!.textContent = p.name;
}
}
}
@WithTemplate('<h1>My Person Object</h1>', 'app')
class Person {
name = 'Max';
constructor() {
console.log('Creating Person object...');
}
}
const pers = new Person();
여러 개의 Decorator Factory 추가하기
- 여러 개의 decorator factory를 추가하는 경우, factory 함수들이 먼저 실행되고(선언한 순서대로) 그 이후에 decorator들이 실행됨(아래에서 위순으로)
function Logger(logString: string) {
console.log('Logger Factory');
return function(constructor: Function) {
console.log(logString);
console.log(constructor);
}
}
function WithTemplate(template: string, hookId: string) {
console.log('WithTemplate Factory');
return function(constructor: any) {
const hookEl = document.getElementById(hookId);
const person = new constructor();
if (hookEl) {
hookEl.innerHTML = template;
hookEl.querySelector('h1')!.textContent = p.name;
}
}
}
@Logger('Login - Person')
@WithTemplate('<h1>My Person Object</h1>', 'app')
class Person {
name = 'Max';
constructor() {
console.log('Creating Person object...');
}
}
const pers = new Person();
Property Decorator
- property decorator는 클래스의 일부분이므로 클래스를 정의할 때 실행됨
function Log(target: any, propertyName: string | Symbol) {
console.log('Property decorator!');
console.log(target, propertyName);
}
class Product {
@Log
title: string;
private _price: number;
set price(val: number) {
if (val > 0) {
this._price = val;
}
}
constructor(t: string, p: number) {
this.title = t;
this._price = p;
}
getPriceWithTax(tax: number) {
return this._price * (1 + tax);
}
}
Accessor Decorator & Parameter Decorator
Accessor Decorator
- acccess decorator는
writable
이 true임
function Log(target: any, propertyName: string | Symbol) {
console.log('Property decorator!');
console.log(target, propertyName);
}
function Log2(target: any, name: string, descriptor: PropertyDecorator) {
console.log('Access decorator!');
console.log(target);
console.log(name);
console.log(descriptor);
}
class Product {
@Log
title: string;
private _price: number;
@Log2
set price(val: number) {
if (val > 0) {
this._price = val;
}
}
constructor(t: string, p: number) {
this.title = t;
this._price = p;
}
getPriceWithTax(tax: number) {
return this._price * (1 + tax);
}
}
Paramter Decorator
function Log(target: any, propertyName: string | Symbol) {
console.log('Property decorator!');
console.log(target, propertyName);
}
function Log2(target: any, name: string, descriptor: PropertyDecorator) {
console.log('Access decorator!');
console.log(target);
console.log(name);
console.log(descriptor);
}
function Log3(target: any, name: string, descriptor: PropertyDecorator) {
console.log('Method decorator!');
console.log(target);
console.log(name);
console.log(descriptor);
}
function Log4(target: any, name: string | Symbol, position: number) {
console.log('Paramter decorator!');
console.log(target);
console.log(name);
console.log(position);
}
class Product {
@Log
title: string;
private _price: number;
@Log2
set price(val: number) {
if (val > 0) {
this._price = val;
}
}
constructor(t: string, p: number) {
this.title = t;
this._price = p;
}
@Log3
getPriceWithTax(@Log4 tax: number) {
return this._price * (1 + tax);
}
}