TypeScript 5.0의 Decorator 정식 지원과 실무 적용기

배경

회사 프로젝트에서 NestJS를 사용하고 있었는데, TypeScript 5.0으로 업그레이드하면서 데코레이터 관련 경고가 발생하기 시작했다. experimentalDecorators 옵션이 여전히 필요했지만, 이제 표준 데코레이터가 정식 지원되면서 마이그레이션을 검토하게 되었다.

기존 레거시 데코레이터

// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

NestJS의 DI 시스템은 reflect-metadata에 의존하고 있어서 당장 옵션을 제거할 수는 없었다.

새로운 표준 데코레이터

TypeScript 5.0의 표준 데코레이터는 ECMAScript Stage 3 제안을 따른다. 가장 큰 차이는 시그니처가 완전히 바뀌었다는 점이다.

// 표준 데코레이터 (TS 5.0+)
function logged(value: Function, context: ClassMethodDecoratorContext) {
  const methodName = String(context.name);
  
  return function(this: any, ...args: any[]) {
    console.log(`Calling ${methodName}`);
    return value.apply(this, args);
  };
}

class API {
  @logged
  fetch() {
    return 'data';
  }
}

실무 적용의 한계

결론부터 말하면 아직 프로덕션에 전면 적용하지는 못했다.

  1. NestJS 비호환: 현재 NestJS는 여전히 레거시 데코레이터 기반이다
  2. 메타데이터 누락: emitDecoratorMetadata가 표준 데코레이터에서는 동작하지 않는다
  3. 라이브러리 생태계: TypeORM, class-validator 등 주요 라이브러리들이 아직 마이그레이션 중이다

제한적 활용

프레임워크에 의존하지 않는 유틸리티 코드에는 적용할 수 있었다.

// 로깅 데코레이터
function measure(value: Function, context: ClassMethodDecoratorContext) {
  return function(this: any, ...args: any[]) {
    const start = performance.now();
    const result = value.apply(this, args);
    console.log(`${String(context.name)}: ${performance.now() - start}ms`);
    return result;
  };
}

정리

표준 데코레이터는 분명 더 명확한 API를 제공하지만, 실무에서는 생태계가 따라올 때까지 기다려야 할 것 같다. 당분간은 experimentalDecorators를 유지하면서 점진적으로 전환을 준비하는 방향으로 가닥을 잡았다.