데코레이터
데코레이터는 클래스, 속성, 메서드, 접근 제어자, 매개변수 등에 사용할 수 있는 특별한 함수입니다. 선언된 데코레이터 함수를 사용할 때는 데코레이터 이름 앞에 @
를 붙입니다.
// 데코레이터 함수
function Component(target:Function) {
console.log(target);
console.log(target.prototype);
}
// 데코레이터를 사용한 클래스 TabsComponent 정의
@Component
class TabsComponent {}
클래스, 속성, 메서드, 접근자, 매개변수에 따라 데코레이터 함수가 전달 받는 인자는 각각 다릅니다.
Decorator Factory
함수 사용 시, 사용자가 인자를 전달할 수 있는 것과 유사하게, 데코레이터 함수 또한 팩토리를 사용해 사용자로부터 인자를 전달 받도록 설정할 수 있습니다. 데코레이터 팩토리 함수는 데코레이터 함수를 감싸는 래퍼 함수입니다. 팩토리는 사용자로부터 전달 받은 인자를, 내부에서 반환되는 데코레이터 함수는 데코레이터로 사용됩니다
// 데코레이터 팩토리
function Component(value:string) {
console.log(value);
// 데코레이터 함수
return function(target:Function) {
console.log(target);
console.log(target.prototype);
}
}
// 데코레이터 팩토리를 사용하면 값을 전달할 수 있습니다.
@Component('tabs')
class TabsComponent {}
// TabsComponent 객체 생성
const tabs = new TabsComponent();
실행흐름
데코레이터의 실행 흐름은 다음 순으로 처리됩니다.
- 각 데코레이터 표현식은 위에서 아래 방향으로 평가됩니다.
- 결과는 아래에서 위로 함수를 호출합니다.
// Size 데코레이터 팩토리
function Size() {
console.log('Size(): 평가됨');
// Size 데코레이터
return function(target:any, prop:string, desc:PropertyDescriptor){
console.log('Size(): 실행됨')
}
}
// Color 데코레이터 팩토리
function Color() {
console.log('Color(): 평가됨');
// Color 데코레이터
return function(target:any, prop:string, desc:PropertyDescriptor){
console.log('Color(): 실행됨')
}
}
// Button 클래스 정의
class Button {
// 메서드에 멀티 데코레이터 적용
@Size()
@Color()
isPressed() {}
}
console에 출력되는 결과는 다음과 같습니다.
> Size(): 평가됨
> Color(): 평가됨
> Color(): 실행됨
> Color(): 실행됨
클래스 데코레이터
클래스에 설정하는 데코레이터를 말합니다. 클래스 데코레이터가 설정된 클래스 선언을 과찰, 수정 또는 대체하는데 사용할 수 있습니다. 클래스 데코레이터는 런타임에 함수로 호출 되며, 데코레이팅 되는 클래스가 유일한 인자로 전달되어 호출됩니다.
// Component 데코레이터
function Component(target:Function) {
// 프로토타입 객체 참조
let $ = target.prototype;
// 프로토타입 객체 확장
$.type = 'component';
$.version = '0.0.1';
}
// Component 데코레이터 사용
@Component
class TabsComponent {};
// TabsComponent 객체 인스턴스 생성
const tabs = new TabsComponent();
// 데코레이터로 설정된 프로토타입 확장은
// 타입 단언(Type Assertion) 필요
console.log((tabs as any).type); // 'component' 출력
메서드 데코레이터
메서드 데코레이터는 메서드 선언 앞에 사용됩니다. 데코레이터는 메서드 선언을 확인, 수정, 교체하는데 사용될 수 있습니다. 메서드 데코레이터 함수가 전달 받는 인자는 총 3가지로 다음과 같습니다.
- target:
any
- prop:
string
- descriptor:
PropertyDescriptor
// Write 데코레이터 팩토리
function Write(able:boolean = true) {
// Write 데코레이터
return function(t:any,p:string,d:PropertyDescriptor) {
d.writable = able;
}
}
// Button 클래스
class Button {
// 생성자
constructor(public el:HTMLButtonElement){}
// Write 데코레이터 사용
// false 전달 ⟹ 쓰기 불가
@Write(false)
disable(){ this.el.setAttribute('disabled', 'disabled'); }
}
// Button 객체 인스턴스 생성 및 변수 참조
const btn = new Button( <HTMLButtonElement>document.querySelector('.button') );
// [오류]
// 쓸 수 없는 메서드를 쓰려고 하였기에 쓸 수 없다고 오류 메시지를 출력합니다.
// Uncaught TypeError:
// Cannot assign to read only property 'disable' of object '#<Button>'
btn.disable = function() { console.log(this); };
접근 제어자 데코레이터
접근 제어자 데코레이터는 접근 제어자 앞에 사용됩니다. 접근 제어자 데코레이터는 접근 제어자에 대한 선언 확인, 수정, 교체하는데 사용될 수 있습니다. 접근 제어자 데코레이터 함수가 전달 받는 인자는 총 3가지로 다음과 같습니다.
- target:
any
- prop:
string
- descriptor:
PropertyDescriptor
속성 데코레이터
속성 데코레이터는 속성 선언 앞에 사용됩니다. 속성 데코레이터는 속성 선언을 확인, 수정, 교체하는데 사용될 수 있습니다. 앞에서 다룬 메서드, 접근 제어자와 달리 속성 데코레이터 함수는 전달 받는 인자가 총 2가지 입니다.
- target:
any
- prop:
string
매개변수 데코레이터
매개변수 데코레이터는 메서드 선언 앞에 사용됩니다. 매개변수 데코레이터는 클래스 생성자 함수 또는 메서드의 매개변수 에 사용될 수 있습니다. 매개변수 데코레이터 함수는 전달 받는 인자가 총 3가지 입니다.
- target:
any
- prop:
string
- parameter_index:
number
// Log 매개변수 데코레이터
function Log(t:any, p:string, i:number) {
console.log(t.name);
console.log(`
매개변수 순서: ${i},
멤버 이름: ${p === undefined ? 'constructor' : p}
`);
}
// Button 클래스
class Button {
el:HTMLButtonElement;
color:string;
// 생성자 함수 내에 Log 데코레이터 사용
constructor(
@Log el:HTMLButtonElement,
@Log color:string = 'transparent'
) {
this.el = el;
this.color = color;
}
// 스태틱 메서드 내에 Log 데코레이터 사용
static initialize(
@Log els:NodeList,
@Log color:string = 'transparent'
){
return [].slice.call(els).map(el => new Button(el, color));
}
}
// Button.initialize() 스태틱 메서드 사용
const btns = Button.initialize( document.querySelectorAll('.button'), '#900' );
'프론트엔드 스터디 > Typescript' 카테고리의 다른 글
[TypeScript] 기초 - 유니온 타입(Union Type) (0) | 2021.07.21 |
---|---|
[TypeScript] 기초 - 리터럴 타입 (0) | 2021.07.20 |
[TypeScript] 기초 - 인터페이스(Interface) (0) | 2021.07.20 |
[TypeScript]기초 - 기본 타입 (0) | 2021.07.20 |
[TypeScript] 기초 - 타입스크립트를 왜 써야할까? (0) | 2021.07.05 |