TypeScript 4.2 Template Literal Types로 타입 안정성 개선하기

배경

사내 관리자 페이지를 리팩토링하면서 API 엔드포인트 타입 정의가 필요했다. /api/users/:id, /api/products/:id 같은 동적 경로가 많았는데, 기존에는 그냥 string으로 처리했다.

TypeScript 4.2의 Template Literal Types를 적용하면서 이 부분을 개선할 수 있었다.

적용 사례

API 경로 타입

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiVersion = 'v1' | 'v2';
type Resource = 'users' | 'products' | 'orders';

type ApiRoute = `/api/${ApiVersion}/${Resource}`;
type ApiRouteWithId = `${ApiRoute}/${number}`;

// 자동완성과 타입 체크가 동작한다
const route: ApiRoute = '/api/v1/users'; // OK
const route2: ApiRoute = '/api/v3/users'; // Error

Tailwind CSS 클래스 조합

type Size = 'sm' | 'md' | 'lg';
type Color = 'primary' | 'secondary' | 'danger';
type ButtonClass = `btn-${Size}-${Color}`;

const getButtonClass = (size: Size, color: Color): ButtonClass => {
  return `btn-${size}-${color}`;
};

실무 효과

  1. 오타 방지: API 경로 문자열 하드코딩 시 발생하던 오타를 컴파일 타임에 잡았다
  2. 자동완성: IDE에서 가능한 조합을 제안해줘서 생산성이 올랐다
  3. 리팩토링 안정성: 경로 변경 시 타입 에러로 즉시 파악 가능했다

한계

  • 너무 많은 조합은 성능 이슈가 있다 (컴파일 느려짐)
  • 동적 값(string)과 섞이면 타입 추론이 깨진다
  • 런타임 검증은 별도로 필요하다

정리

Template Literal Types는 제한된 문자열 패턴을 다룰 때 유용했다. 특히 설계 단계에서 가능한 값의 범위가 명확한 경우 적용하면 좋다. 다만 과도하게 사용하면 컴파일 속도에 영향을 주니 주의가 필요하다.

TypeScript 4.2 Template Literal Types로 타입 안정성 개선하기