Lsiron
Type Script의 데코레이터란? 본문
Type Script에서 사용되는 데코레이터 문법에 대해 알아보자.
nest.js 를 사용할 때 온통 @ 투성이로 되어있어서 무엇인가 했는데 데코레이터 문법이였다.
먼저 데코레이터의 사용법에 대해 간단하게 알아보자.
Type Sciprt에서 데코레이터는 실험적인 기능이다. (정식기능 아님)
그렇기 때문에, 데코레이터를 사용하기 위해서는 tsconfig.json파일에 아래 코드를 입력 해 주어야 한다.
{
"compilerOptions": {
"experimentalDecorators": true,
},
}
위 코드는 데코레이터 옵션을 활성화 시켜준다.
이제 아무 ts 파일에 가서 class를 하나 만들어보고 출력해보자.
class Siron {
name = '아니 무슨'
constructor() {
console.log(this.name + '이런게 다 있지');
}
}
const siron = new Siron();
이렇게 class만 사용하면 다음과 같이 출력된다.
function lsiron(constructor: Function) {
console.log(constructor)
}
@lsiron
class Siron {
name = '아니 무슨'
constructor() {
console.log(this.name + '이런게 다 있지');
}
}
const siron = new Siron();
허나 위 예시처럼 constructor(생성자 함수)를 인자로 받고, 타입을 Function으로 지정하여 모든 함수 타입을 포함하는 타입으로 지정 해 준 뒤, class에 @(at)과 함수명 lsiron 을 달아주면 다음과 같이 출력된다.
( 데코레이터 문법 사용법 )
참고로 클래스는 본질적으로 함수이다. ( https://lsiron.tistory.com/81 참조 )
즉, lsiron 함수의 인자로 클래스를 넣어준 것이나 다름없다. ( class = constructor = 생성자함수 )
데코레이터 문법을 사용하지 않았을 때는 class 문법이 적용된 Siron의 결과물만 출력이 된다.
허나 데코레이터 문법을 사용했을 때는 class 문법이 적용된 Siron의 결과물과 lsiron 함수 기능이 함께 작동하는 것을 볼 수 있다.
즉, class문법과 class가 인자로 들어간 함수가 함께 작동 하는 것이다.
이 점을 미루어보았을 때
데코레이터 문법이란 함수를 미리 정의해두고, 그 함수를 클래스에 적용하여 추가적인 기능을 부여하는 문법이라고 할 수 있겠다.
그럼 이제 데코레이터가 무엇인지 그리고 왜 사용하며, 언제 사용해야하는지 알아보자.
데코레이터의 개념
Type Script에서 데코레이터는 함수인데, 특정 함수를 호출할 때 추가적인 기능을 제공해주는 문법이다.
데코레이터는 주로 클래스, 클래스 메서드, 클래스 속성, 클래스 접근자, 클래스 매개변수에 적용되도록 설계되어 있다.
데코레이터는 클래스 기반 프로그래밍에서 동작하도록 설계된 문법이기 때문에, 클래스 없이 사용하는 것은 불가능하다.
결국, 데코레이터를 활용하려면 클래스가 있어야 한다.
데코레이터 함수는 데코레이터가 적용된 클래스에 대한 정보를 인자로 받아서, 해당 선언을 수정하거나 추가적인 동작을 할 수 있다.
데코레이터의 사용 이유
- 메타프로그래밍: 코드의 특정 부분에 대한 메타데이터를 추가할 수 있다.
- 로깅: 메소드 호출, 클래스 인스턴스화 등을 로그할 수 있다.
- 권한 검사: 메소드 호출 전에 권한을 검사할 수 있다.
- 의존성 주입: 클래스 인스턴스화 시 의존성을 주입할 수 있다.
언제 사용해야 할까 ?
- 반복적인 작업을 줄이고 싶을 때: 데코레이터는 여러 클래스나 메소드에 동일한 기능을 적용할 때 유용하다.
- 코드의 가독성을 높이고 싶을 때: 데코레이터를 사용하면 코드가 더 간결해지고 읽기 쉬워진다.
- 기능을 확장하고 싶을 때: 클래스나 메소드의 기능을 확장하기 위해 데코레이터를 사용할 수 있다.
예시(★★★)
1. 클래스 데코레이터
클래스 데코레이터는 클래스 선언 직전에 사용되어, 클래스의 생성자 함수에 대해 작업을 수행한다.
보통 로깅, 메타데이터 추가, 클래스의 인스턴스 생성로직 수정 등을 위해 사용된다.
클래스 데코레이터는 클래스(생성자 함수)를 인자로 받는다.
위에서 말했듯이 클래스는 함수이다. ( class = constructor = 생성자함수 )
function logClass(target: Function) {
console.log(`Target: ${target}`);
}
@logClass
class MyClass {
constructor() {
console.log('진짜 뭔 이렇게 다 있냐');
}
}
const myInstance = new MyClass();
- logClass 함수는 클래스 데코레이터이다.
- 이 데코레이터는 target이라는 하나의 인자를 받는다.
- target: MyClass 클래스 자체(생성자 함수).
- 데코레이터는 이 인자를 콘솔에 출력한다.
- @logClass 데코레이터는 MyClass 클래스에 적용된다.
- 클래스가 정의될 때 데코레이터가 실행되고, 다음과 같은 출력이 나타난다.
2. 메소드 데코레이터
메서드 데코레이터는 메서드 정의 직전에 사용되어, 메서드의 속성과 동작을 수정할 수 있다.
보통 메서드 호출 전후에 로깅, 접근 제어, 유효성 검사 등을 추가할 때 사용된다.
메소드 데코레이터는 다음 세 가지 인자를 받는다.
- target: 데코레이터가 적용된 메소드가 속한 클래스의 프로토타입 객체이다.
- propertyKey: 데코레이터가 적용된 메소드의 이름이다.
- descriptor: 메소드의 PropertyDescriptor 객체로, 메소드의 속성을 설명한다.
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Target: ${target}`);
console.log(`Property Key: ${propertyKey}`);
console.log(`Descriptor: ${JSON.stringify(descriptor)}`);
}
class MyClass {
@logMethod
greet() {
console.log('어이가 없네');
}
}
const myclass = new MyClass(); // 인스턴스 만들기
myclass.greet(); // 메서드 호출하기
- logMethod 함수는 메소드 데코레이터이다.
- 이 데코레이터는 세 개의 인자를 받는다.
- target: MyClass의 프로토타입 객체.
- propertyKey: 'greet' 문자열, 메소드의 이름.
- descriptor: 메소드의 PropertyDescriptor 객체, 메소드의 속성을 설명한다.
- 데코레이터는 단순히 이 인자들을 콘솔에 출력한다.
- @logMethod 데코레이터는 greet 메소드에 적용된다.
- 클래스가 정의될 때 데코레이터가 실행되고, 다음과 같은 출력이 나타난다.
참고로 왜 target이 [object Object] 로 출력되냐면,
[object Object]는 JavaScript에서 객체를 문자열로 표현할 때 기본적으로 나타나는 형태이다.
이는 객체를 문자열로 변환할 때 객체의 타입을 나타내는 기본 문자열 표현이다.
JavaScript의 Object.prototype.toString 메서드가 호출되면, 이 기본 문자열 형식으로 객체를 나타낸다.
console.log는 기본적으로 객체를 출력할 때 그 객체의 toString 메서드를 호출한다.
target 인자는 클래스의 프로토타입 객체를 가리키는데, 프로토타입 객체를 문자열로 변환하면 [object Object]가 된다.
이는 JavaScript의 기본 동작이다.
한번 target(MyClass의 프로토타입 객체)의 생성자 함수를 출력해보자.
( class = constructor = 생성자함수 )
target 인자에 target.constructor 을 넣어 줄 것이다.
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log(`Target: ${target.constructor}`);
console.log(`Property Key: ${propertyKey}`);
console.log(`Descriptor: ${JSON.stringify(descriptor)}`);
}
class MyClass {
@logMethod
greet() {
console.log('어이가 없네');
}
}
const myclass = new MyClass(); // 인스턴스 만들기
myclass.greet(); // 메서드 호출하기
target은 MyClass의 프로토타입 객체 이기 때문에 생성자함수를 찍으면 당연히 MyClass가 다시 나온다.
( class = constructor = 생성자함수 )
Class를 하나 만들어놓으면 기계처럼 객체를 계속 찍어낼 수 있는 이유이다.
프로토타입으로 인해 위와 같이 무한하게 계속 이어진다. ( 예시는 https://lsiron.tistory.com/81 여기에서 가져왔다. )
3. 속성 데코레이터
속성 데코레이터는 클래스 속성에 적용되며, 속성의 메타데이터를 수정할 수 있다.
보통 메타데이터 추가, 디폴트 값 설정, 접근 제어 등을 위해 사용된다.
속성 데코레이터는 다음 두 가지 인자를 받는다.
- target: 데코레이터가 적용된 속성이 속한 클래스의 프로토타입 객체이다.
- propertyKey: 데코레이터가 적용된 속성의 이름이다.
function logProperty(target: any, propertyKey: string) {
console.log(`Target: ${target}`);
console.log(`Property Key: ${propertyKey}`);
}
class MyClass {
@logProperty
myProperty: string;
}
- logProperty 함수는 속성 데코레이터이다.
- 이 데코레이터는 두 개의 인자를 받는다.
- target: MyClass의 프로토타입 객체.
- propertyKey: 'myProperty' 문자열, 속성의 이름.
- 데코레이터는 이 인자들을 콘솔에 출력한다.
- @logProperty 데코레이터는 myProperty 속성에 적용된다.
- 클래스가 정의될 때 데코레이터가 실행되고, 다음과 같은 출력이 나타난다.
4. 매개변수 데코레이터
매개변수 데코레이터는 메서드 매개변수에 적용되어, 매개변수에 대한 메타데이터를 추가할 수 있다.
보통 매개변수에 대한 유효성 검사, 메타데이터 추가 등을 위해 사용된다.
매개변수 데코레이터는 다음 세 가지 인자를 받는다.
- target: 데코레이터가 적용된 메소드가 속한 클래스의 프로토타입 객체이다.
- propertyKey: 데코레이터가 적용된 메소드의 이름이다.
- parameterIndex: 데코레이터가 적용된 매개변수의 인덱스(위치)이다.
function logParameter(target: any, propertyKey: string, parameterIndex: number) {
console.log(`Target: ${target}`);
console.log(`Property Key: ${propertyKey}`);
console.log(`Parameter Index: ${parameterIndex}`);
}
class MyClass {
myMethod(@logParameter param1: string) {
console.log(`param1: ${param1}`);
}
}
const myInstance = new MyClass();
myInstance.myMethod('와 진짜....이게뭐야');
- logParameter 함수는 매개변수 데코레이터이다.
- 이 데코레이터는 세 개의 인자를 받는다.
- target: MyClass의 프로토타입 객체.
- propertyKey: 'myMethod' 문자열, 메소드의 이름.
- parameterIndex: 0, 데코레이터가 적용된 매개변수의 인덱스.
- 데코레이터는 이 인자들을 콘솔에 출력한다.
- @logParameter 데코레이터는 myMethod 메소드의 첫 번째 매개변수(param1)에 적용된다.
- 클래스가 정의될 때 데코레이터가 실행되고, 다음과 같은 출력이 나타난다.
데코레이터 함수가 정해진 인자를 받지 않거나 제대로 사용하지 않으면 데코레이터가 의도한 대로 작동하지 않는다.
'언어 > Type Script' 카테고리의 다른 글
Type Script 에서 조건문으로 타입만들기, infer (0) | 2024.07.18 |
---|---|
Type Script 의 Object 심화 (index signature, recursive, keyof, 타입변환기) (0) | 2024.07.18 |
Type Script 의 implements ? (0) | 2024.07.18 |
Type Script 에서 d.ts 파일이란? 그리고 외부 js 라이브러리 가져오기 (0) | 2024.07.18 |
Type Script 에서 외부 자바스크립트 파일을 사용할 때 (declare, ambient module / local module) (0) | 2024.07.17 |