Decorators는 현재(2023/04)기준 Stage 3단계(4단계가 표준 추가)인 ECMAScript 공식 스펙이다. ES2024의 유력한 기능 중 하나이다.
위와 같은 간단한 Person 클래스의 greet 함수를 디버깅 하기 위해 함수 내부 시작과 끝에 console.log를 추가할 경우 데코레이터를 사용하면 편리하게 작업할수 있다.
이로써 모든 함수에 @loggedMethod만 추가하면 쉽게 정해진 로그 메서드를 사용할수 있다.
이 외에도 컨택스트 객체에는 addInitializer라는 유용한 함수가 있다. 이는 생성자의 시작 부분(또는 정적 클래스 자체의 초기화)에 연결할 수 있다.
자바스크립트를 사용하면서 this가 다시 바인딩 되지 않도록 아래와 같은 코딩 스타일을 자주 사용한다.
이를 데코레이터로 사용하면 일관된 로직을 추가/변경해 적용할수 있게 된다.
여기서 유의할 점은 데코레이터는 '역순'으로 실행된다는 점이다. 위 예를 보면, @loggedMethod가 greet 메서드를 꾸미고, @bound가 @loggedMethod의 결과를 꾸미게 된다. 데코레이터가 사이드 이펙트를 가지거나 보장된 순서를 원할 경우 유의해야 한다.
실험적 레거시 데코레이터와의 차이점
기존에 타입스크립트는 실험적 데코레이터를 지원하고 있었으며 --experimentalDecorators 옵션으로 활성화 할수 있었다.
실험적 데코레이터와 v5 데코레이터(ECMA)의 차이는 매개변수에 데코레이터를 지정하거나, --emitDecoratorMetadata와 호환되지 않는 등이 있다. 앞으로 데코레이터의 제안에 해당 내용들을 추가해 간격을 좁혀나갈 예정이다.
데코레이터를 export 앞에 놓을 수 있게 되면서 다양하게 선언이 가능해졌지만, 양옆으로 놓을수는 없다.
데코레이터의 타입을 보장하기 위해서는 상당히 복잡한 타입정의가 될수 있다. 이는 가독성과 상충관계가 있기 때문에 단순하게 유지하라고 조언한다. 데코레이터의 메커니즘에 대해 자세한 내용은 이 글에 정리되어 있다.
const Type Parameters
객체의 타입을 추론할때 타입스크립트는 일반적인 타입을 선택한다. 따라서 위의 예에서 names는 string[] 타입으로 추론된다.
readonly 타입을 반환하게 할 경우 기존까지는 as const타입 어설션으로 강제화 해주어야 했는데, 이는 상당히 번거롭다.
이제 const 타입 파라미터를 사용해 as const 추론이 가능해졌다. 하지만 이는 함수 호출 내에 작성된 객체, 배열, 표현식에만 영향을 미치므로 주소값을 넘기는 인수로는 동작할수 없음을 알아두어야 한다.
Supporting Multiple Configuration Files in extends
extends 필드에 배열로 여러개의 config 파일을 지원하게 되었다. 개인적으로 상당히 만족
All enums Are Union enums
모든 enum은 union된 enum이다. 타입스크립트가 처음 enum을 도입했을 때만 해도 enum은 상수 집합에 불과했다(number 타입). 하지만 타입스크립트 2.0에서 enum 리터럴 타입(고유한 값; 상수 10, 20 등이 타입이 됨)이 도입되면서 리터럴 타입은 각 enum 멤버에 고유한 타입을 부여하게 된다.
각 enum 멤버에 고유한 타입을 부여할 때 발생하는 한 가지 문제는 해당 타입이 멤버의 실제 값과 연관되어 있다는 점이다.
예를 들어 아래와 같이 enum 멤버가 함수 호출로 초기화될 수 있는 경우, 값을 계산할수 없으므로 초기화 이전까지는 에러가 발생한다. 또한 enum E의 예시와 같이 const a:E는 3 | 4의 타입이 아닌 number가 된다. 이는 리터럴 타입의 장점을 사용하지 못하고 기존 상수 집합을 사용하고 있다는 뜻이 된다.
이제 타입스크립트 5버전 부터는 각 멤버에 대해 고유한 타입을 생성하여 enum 멤버를 union enum으로 사용할수 있게 되었다. 즉, enum의 모든 멤버를 좁혀서 그 멤버를 타입으로 참조할 수 있게 되었다.
--moduleResolution bundler
대부분의 최신 번들러는 Node.js에서 ECMAScript 모듈과 CommonJS 조회 규칙의 융합을 사용한다. 번들러의 작동 방식을 모델링하기 위해 타입스크립트는 이제 새로운 전략인 --moduleResolution 번들러를 도입한다.
하이브리드 조회 전략을 구현하는 Vite, esbuild, swc, Webpack, Parcel 등의 최신 번들러를 사용 중이라면 새로운 bundler옵션이 적합하다.
Support for export type *
타입스크립트에서 export type * 문법이 가능해졌다. 이를 통해 타입과 값의 분리가 더 명확해졌다.
@overload Support in JSDoc
기존에 코드로 표현해야 했던 부분을 jsdoc으로 나누어서 표현(example 등)할수 있기 때문에 DX의 향상에 기대가 된다.
Speed, Memory, and Package Size Optimizations
지표에서도 눈에 띄일만큼 변경사항이 있으며 원문 블로그 자체에서도 대부분의 코드베이스에서 10~20% 정도 속도 향상을 느낄 수 있다고 자신하고 있기 때문에 모노레포에서 타입 참조 시간을 많이 줄일수 있을 것이라 기대하고 있다.
Breaking Changes and Deprecations
Runtime Requirements
타입스크립트는 이제 ECMAScript 2018을 대상으로 한다. 최소 엔진은 12.20으로 설정되었다.
lib.d.ts Changes
DOM의 유형이 생성되는 방식이 변경되어 기존 코드에 영향을 미칠 수 있다. 특히 특정 프로퍼티가 숫자에서 숫자 리터럴 타입으로 변환되었으며, 잘라내기, 복사, 붙여넣기 이벤트 처리를 위한 프로퍼티와 메서드가 인터페이스 전반으로 이동되었다.
API Breaking Changes
TypeScript 5.0에서는 모듈로 전환하고, 불필요한 인터페이스를 제거했으며, 일부 정확성을 개선했다.
Forbidden Implicit Coercions in Relational Operators
TypeScript의 특정 연산은 암시적으로 문자열을 숫자로 강제 변환할 수 있는 코드를 작성할 경우 이미 경고한다. 5.0에서는 관계 연산자(<,>,<=,=>)에도 적용된다.
+ 연산자를 통해 명시적 형변환후 사용하는것은 가능하다.
Enum Overhaul
enum을 이해하는 개념 수를 줄이기 위해 위의 두 가지 오류가 추가되었다.
마무리
decorator 추가 및 enum 명시성 확장, multi extends, jsdoc 등 다양한 편의성이 추가되었기 때문에 기대되는 메이저 업데이트이다.