@
로 시작하는 데코레이터를 선언하면 데코레이터로 구현된 코드를 함께 실행한다.ex)
class CreateUserDto {
@IsEmail() //이메일 형식을 가진 문자열 확인
@MaxLength(60) //길이 최대 60자 확인
readonly email: string;
@IsString() //password는 문자열
@Matches(/^[A-Za-z\d!@#$%^&*()]{8,30}$/) //정규표현식
readonly password: string; //readonly : 읽기전용 타입
}
tsconfig.json
{
"compilerOptions": {
...
"experimentalDecorators": true, //true로 해줘야 데코레이터 사용 가능
...
}
}
여러개의 데코레이터를 사용한다면 수학에서의 함수 합성과 같이 적용
f(g(x))
@f
@g
test
function first() {
console.log("first(): factory evaluated"); //1
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("first(): called"); //4
};
}
function second() {
console.log("second(): factory evaluated"); //2
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("second(): called"); //3
};
}
class ExampleClass {
@first()
@second()
method() {
console.log('method is called'); //5
}
}
//<result>
first(): factory evaluated
second(): factory evaluated
second(): called
first(): called
method is called
//클래스 데코레이터 팩토리
function reportableClassDecorator<T extends { new (...args: any[]): {} }>(constructor: T) { //T:제너릭타입
return class extends constructor {
reportingURL = "http://www.example.com";
};
}
@reportableClassDecorator
class BugReport {
type = "report";
title: string;
constructor(t: string) {
this.title = t;
}
}
const bug = new BugReport("Needs dark mode");
console.log(bug);
//<result>
{type: 'report', title: 'Needs dark mode', reportingURL: 'http://www.example.com'}
function HandleError() {
//메서드 데코레이터가 가져야 하는 3개의 인자
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { //descriptor는 해당 속성의 설명자 객체, PropertyDescriptor는 밑에서 설명
console.log(target)
console.log(propertyKey)
console.log(descriptor)
const method = descriptor.value;
descriptor.value = function() {
try {
method();
} catch (e) {
// 에러 핸들링 로직 구현
console.log(e);
}
}
};
}
class Greeter {
@HandleError()
hello() {
throw new Error('테스트 에러');
}
}
const t = new Greeter();
t.hello();
PropertyDescriptor
: 객체 속성의 특성을 기술하고 있는 객체
interface PropertyDescriptor {
configurable?: boolean; // 속성의 정의를 수정할 수 있는지 여부
enumerable?: boolean; // 열거형인지 여부
value?: any; // 속성 값
writable?: boolean; // 수정 가능 여부
get?(): any; // getter
set?(v: any): void; // setter
}
function Enumerable(enumerable: boolean) { // enumerable 속성을 데코레이터 인자로 결정
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = enumerable;
}
}
class Person {
constructor(private name: string) {}
@Enumerable(true) //열거가능
get getName() {
return this.name;
}
@Enumerable(false) // 열거불가능
set setName(name: string) {
this.name = name;
}
}
const person = new Person('jimin');
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}
//<result>
name: jimin
getName: jimin
//setName은 열거하지 못하게 되었기 때문에 for문에서 key로 받을 수 없다.
function format(formatString: string) {
return function (target: any, propertyKey: string): any {
let value = target[propertyKey];
function getter() {
return `${formatString} ${value}`;
} //데코레이터 인자로 들어온 formatString을 원래의 속성과 조합한 스트링으로 변환
function setter(newVal: string) {
value = newVal;
}
return {
get: getter,
set: setter,
enumerable: true,
configurable: true,
}
}
}
class Greeter {
@format('Hello')
greeting: string;
}
const t = new Greeter();
t.greeting = 'World';
console.log(t.greeting);
//출력 :Hello World
import { BadRequestException } from '@nestjs/common';
function MinLength(min: number) { //파라미터의 최소값을 검사하는 파라미터 데코레이터
return function (target: any, propertyKey: string, parameterIndex: number) {
target.validators = { // validators 속성에 유효성을 검사하는 함수 할당
minLength: function (args: string[]) {
return args[parameterIndex].length >= min;
}
}
}
}
//유효성 검사 : parameterIndex에 위치한 인자의 길이가 최소값보다 같거나 큰지 검사
function Validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const method = descriptor.value;
descriptor.value = function(...args) {
Object.keys(target.validators).forEach(key => {
if (!target.validators[key](args)) {
throw new BadRequestException();
}
})
method.apply(this, args);
}
}
class User {
private name: string;
@Validate
setName(@MinLength(3) name: string) { //최소길이 3으로 지정
this.name = name;
}
}
const t = new User();
t.setName('jimin'); // 길이가 3이상이라 문제없음
console.log('----------')
t.setName('ji'); //길이가 3보다 작기 때문에 BadRequestException 발생
데코레이터 | 전달되는 인자 | 선언 불가능한 위치 |
---|---|---|
클래스 | constructor | d.ts 파일, declare 클래스 |
메서드 | target,propertyKey,PropertyDescriptor | d.ts 파일,declare 클래스,오버로드 메서드 |
접근자 | target, propertyKey,propertyDescriptor | d.ts 파일,declare클래스 |
속성 | target, propertyKey | d.ts파일, declare 클래스 |
매개변수 | target,propertyKey,parameterIndex | d.ts파일,declare클래스 |