TypeScript 4.2 Template Literal Types로 API 타입 안전성 개선

문제 상황

프로젝트에서 REST API 엔드포인트를 문자열로 관리하다 보니 오타로 인한 404 에러가 종종 발생했다. /api/user/:id 같은 동적 라우트는 타입 체크가 불가능해서 런타임에만 에러를 확인할 수 있었다.

Template Literal Types 적용

TypeScript 4.2에서 추가된 Template Literal Types를 사용해 타입 수준에서 엔드포인트를 검증하도록 변경했다.

type ApiVersion = 'v1' | 'v2';
type Resource = 'users' | 'posts' | 'comments';
type Endpoint = `/api/${ApiVersion}/${Resource}`;

// 유효한 엔드포인트만 허용
const endpoint: Endpoint = '/api/v1/users'; // OK
const invalid: Endpoint = '/api/v3/users'; // Error

동적 파라미터도 타입으로 표현할 수 있었다.

type UserId = `user-${string}`;
type PostId = `post-${number}`;

type DynamicEndpoint<T extends string> = `/api/v1/${T}/${string}`;

function fetchResource(endpoint: DynamicEndpoint<Resource>) {
  return fetch(endpoint);
}

fetchResource('/api/v1/users/user-123'); // OK
fetchResource('/api/v1/invalid/123'); // Error

실제 적용 예시

API 클라이언트 함수에 적용해서 사용했다.

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiPath = `/api/${string}`;

interface ApiConfig<T = unknown> {
  method: HttpMethod;
  path: ApiPath;
  body?: T;
}

async function apiCall<T>(config: ApiConfig): Promise<T> {
  const response = await fetch(config.path, {
    method: config.method,
    body: config.body ? JSON.stringify(config.body) : undefined,
  });
  return response.json();
}

결과

엔드포인트 오타로 인한 버그가 눈에 띄게 줄었다. 자동완성도 잘 동작해서 개발 경험이 개선됐다. Template Literal Types는 단순해 보이지만 문자열 기반 API 작업에서 꽤 유용했다.

TypeScript 4.2 Template Literal Types로 API 타입 안전성 개선