데코레이터(decorator)
데코레이터(decorator)는 TypeScript의 실험적 기능으로 클래스, 클래스 메서드, 프로퍼티, 메서드 매개변수를 활용한 메타 프로그래밍에 깔끔한 문법을 제공합니다.
데코레이터는 장식하는 대상의 함수를 호출하는 기능을 제공하는 문법입니다.
예제를 통해 데코레이터가 어떻게 동작하는지 알아보겠습니다.
@serializable
class APIPayload {
getValue(): Payload {
// ...
}
}
클래스 데코레이터인 @serializable은 APIPayload 클래스를 감싸고 있으며 선택적으로 이를 대체하는 새 클래스를 반환합니다.
데코레이터를 사용하지 않고 같은 기능을 아래처럼 구현할 수도 있습니다.
let APIPayload = serializable(class APIPayload{
getValue(): Payload(){
// ...
}
})
TypeScript는 데코레이터 타입 각각에 대해 주어진 이름 범위에 존재하는 함수와 해당 데코레이터 타입에 요구되는 시그니처를 필요로 합니다.
TypeScript가 기본으로 제공하는 데코레이터는 없습니다.
즉, 모든 데코레이터는 직접 구현하거나 NPM으로 설치해야 합니다.
모든 종류(클래스, 메서드, 프로퍼티, 함수 매개변수 등)의 데코레이터는 특정 시그니처를 만족하는 일반 함수일 뿐입니다.
예를 들어 @serializable 데코레이터를 구현한 코드입니다.
type ClassConstructor<T> = new (...args: any[]) => T // ①
function serializable<T extends ClassConstructor<{
getValue(): Payload // ②
}>
>(Constructor: T) { // ③
return class extends Constructor { // ④
serialize() {
return this.getValue().toString()
}
}
}
- new()는 TypeScript에서 클래스 생성자를 구조 기반으로 결정하는 수단임을 기억합니다. 클래스 생성자는 extends로 확장할 수 있으며, 인수의 타입은 any의 스프레드(new (... any [])) 여야 합니다.
- @serializable은 Payload를 반환하는 .getValue 메서드를 구현한 모든 클래스를 장식할 수 있습니다.
- 클래스 데코레이터는 한 개의 인수(클래스)를 받는 함수입니다. 데코레이터 함수는 런타임에 원본 클래스를 대체할 데코레이터를 반환하거나 원래 클래스를 그대로 반환합니다.
- 주어진 클래스를 상속한 다음 .serialize 메서드를 추가해서 클래스를 장식합니다.
.serialize를 호출하면 어떻게 될까요?
let payload = new APIPayload
let serialized = payload.serialize() // error TS2339: 'serialize'프로퍼티는 'APIPayload' 타입에 존재하지 않음
TypeScript는 데코레이터가 장식하는 대상의 형태를 바꾸지 않는다고, 즉 메서드나 프로퍼티를 추가하거나 삭제하지 않았다고 가정합니다.
반환된 클래스를 전달된 클래스에 할당할 수 있는지는 컴파일 타임에만 확인하며, 코드를 작성할 때는 데코레이터가 어떻게 확장하는지 추적하지 않습니다.
따라서 TypeScript의 데코레이터 기능이 더 완벽해지기 전까진 데코레이터 대신 일반 함수를 사용할 것을 권합니다.
TSC 플래그: experimentalDecorators
데코레이터는 아직 실험 단계의 기능입니다. 즉, 미래에도 호환된다는 보장이 없고 아예 TypeScript에선 삭제될 수 있으므로 TSC 플래그를 따로 설정해야 사용할 수 있습니다. "experimentalDecorators": true를 설정한 다음 사용하면 됩니다.
'👶 TypeScript' 카테고리의 다른 글
디자인 패턴 - 팩토리 패턴(factory pattern) (0) | 2023.01.17 |
---|---|
final 클래스 흉내 내기 (0) | 2023.01.17 |
믹스인(mixin) (0) | 2023.01.16 |
다형성 (0) | 2023.01.16 |
클래스는 값과 타입을 모두 선언한다 (0) | 2023.01.16 |