프로그래밍/Typescript

TypeScript의 데코레이터: 코드의 재사용성과 가독성을 높이는 강력한 도구

shimdh 2025. 3. 29. 11:24
728x90

TypeScript에서 데코레이터는 클래스, 메서드, 접근자, 프로퍼티 및 매개변수에 추가적인 기능을 부여할 수 있는 특별한 형태의 선언입니다. 이 글에서는 데코레이터의 기본 개념, 종류, 실제 활용 사례를 통해 TypeScript에서 데코레이터가 어떻게 코드의 재사용성과 가독성을 높이는지 살펴보겠습니다.

1. 데코레이터의 기본 개념

기능 확장

데코레이터를 사용하면 기존 클래스나 메서드에 새로운 행동을 추가하거나 수정할 수 있습니다. 예를 들어, 특정 메서드의 실행 시간을 측정하거나, 클래스의 인스턴스가 생성될 때마다 특정 작업을 수행하도록 설정할 수 있습니다.

메타프로그래밍

코드를 실행하는 시점에 동적으로 변형할 수 있어 유연한 구조를 제공합니다. 이는 개발자가 코드의 동작을 런타임에 조정할 수 있게 해주며, 복잡한 로직을 간결하게 표현할 수 있는 방법을 제공합니다.

가독성 향상

애노테이션 스타일로 작성되어 코드가 더 읽기 쉽고 이해하기 쉬워집니다. 데코레이터를 통해 코드의 의도를 명확히 하고, 각 기능이 어떤 역할을 하는지 쉽게 파악할 수 있습니다.

2. 데코레이터의 종류

TypeScript에서는 여러 종류의 데코레이터를 지원합니다:

클래스 데코레이터

클래스를 정의하는 곳에서 사용할 수 있으며, 클래스에 대한 정보를 수정하거나 추가합니다. 클래스 데코레이터는 클래스의 메타데이터를 추가하거나, 클래스의 인스턴스가 생성될 때 특정 작업을 수행하도록 설정할 수 있습니다.

function LogClass(target: Function) {
    console.log(`클래스 ${target.name}이(가) 생성되었습니다.`);
}

@LogClass
class User {
    constructor(public name: string) {}
}

const user = new User("Alice"); // "클래스 User이(가) 생성되었습니다." 출력

메서드 데코레이터

특정 메서드에 대해 동작을 변경하거나 로그를 남길 때 사용됩니다. 메서드 데코레이터를 통해 메서드 호출 시 추가적인 로깅이나 에러 처리를 구현할 수 있습니다.

function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function(...args: any[]) {
        console.log(`메서드 ${propertyKey} 호출됨`);
        return originalMethod.apply(this, args);
    };

    return descriptor;
}

class Calculator {
    @LogMethod
    add(a: number, b: number): number {
        return a + b;
    }
}

const calculator = new Calculator();
calculator.add(5, 10); // "메서드 add 호출됨" 출력 후 결과 15 반환 

접근자 데코레이터

접근자 데코레이터는 클래스의 접근자 프로퍼티에 대한 동작을 수정할 수 있습니다. 이를 통해 프로퍼티의 getter와 setter에 추가적인 로직을 삽입할 수 있습니다.

프로퍼티 데코레이터

프로퍼티 데코레이터는 클래스의 프로퍼티에 대한 메타데이터를 추가하거나 수정할 수 있습니다. 이를 통해 프로퍼티의 초기값을 설정하거나, 특정 조건을 만족할 때만 값을 할당하도록 할 수 있습니다.

매개변수 데코레이터

매개변수 데코레이터는 메서드의 매개변수에 대한 메타데이터를 추가할 수 있습니다. 이를 통해 매개변수의 유효성을 검사하거나, 특정 조건을 만족할 때만 메서드를 호출하도록 할 수 있습니다.

3. 실제 활용 사례

로그 기록

개발 중 디버깅 목적으로 어떤 함수가 언제 호출되었는지 추적하는 용도로 유용합니다. 이를 통해 개발자는 코드의 흐름을 쉽게 파악하고, 문제 발생 시 신속하게 대응할 수 있습니다.

권한 검사

사용자 권한 확인 로직을 중앙 집중화하여 각 메서드마다 반복하지 않고도 일관된 보안을 유지할 수 있습니다. 이를 통해 보안 관련 코드를 간결하게 유지하고, 코드의 중복을 줄일 수 있습니다.

function AuthGuard(roleRequired: string) {
    return function(target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
        const originalMethod = descriptor.value;

        descriptor.value = function(...args:any[]) {
            // 가정 : getUserRole()은 현재 사용자 역할 반환 
            if (getUserRole() !== roleRequired) { 
                throw new Error("권한 없음");
            }
            return originalMethod.apply(this,args);
        };

        return descriptor;
    };
}

class AdminService {
    @AuthGuard("admin")
    deleteUser(userId:string){
        console.log(`${userId} 삭제됨`);
    }
}

위 예제에서는 deleteUser 메서드를 호출하기 전에 해당 사용자에게 필요한 권한이 있는지를 체크하게 됩니다. 이를 통해 보안성을 높이고, 권한이 없는 사용자가 중요한 작업을 수행하지 못하도록 방지할 수 있습니다.

결론

데코레이터는 TypeScript에서 매우 강력하고 유용한 도구입니다. 이를 통해 코드의 재사용성과 가독성을 높일 뿐만 아니라 다양한 기능을 손쉽게 구현할 수 있습니다. 이러한 특징 덕분에 대규모 애플리케이션에서도 효과적으로 관리되고 유지보수될 수 있도록 돕습니다. 데코레이터를 적절히 활용하면 개발자는 더 나은 품질의 코드를 작성할 수 있으며, 팀원 간의 협업도 원활하게 진행될 수 있습니다.

728x90