TypeScript 4.3 template literal types로 타입 안전성 높이기

문제 상황

사내 어드민 대시보드를 리팩토링하던 중 API 엔드포인트 경로 오타로 인한 404 에러가 프로덕션에서 발견됐다. /api/users/${userId}/profile 대신 /api/user/${userId}/profile로 작성한 것이 원인이었다.

// 기존 방식
const getUserProfile = (userId: string) => {
  return fetch(`/api/user/${userId}/profile`); // 오타
};

Template Literal Types 적용

TypeScript 4.3에서 추가된 template literal types를 사용해 타입 레벨에서 경로를 검증하도록 수정했다.

type ApiRoute = 
  | `/api/users/${string}/profile`
  | `/api/users/${string}/settings`
  | `/api/posts/${string}`;

const fetchApi = (route: ApiRoute) => {
  return fetch(route);
};

// 타입 에러 발생
fetchApi(`/api/user/${userId}/profile`);

// 정상 동작
fetchApi(`/api/users/${userId}/profile`);

유틸리티 타입 확장

경로 파라미터를 추출하는 유틸리티 타입도 만들어봤다.

type ExtractParams<T extends string> = 
  T extends `${infer _Start}/${infer Param}/${infer Rest}`
    ? Param | ExtractParams<`/${Rest}`>
    : never;

type UserRouteParams = ExtractParams<'/api/users/:userId/posts/:postId'>;
// 'userId' | 'postId'

결과

  • 컴파일 타임에 잘못된 경로 사용 즉시 감지
  • IDE 자동완성으로 경로 입력 편의성 향상
  • 리팩토링 시 경로 변경에 대한 안전성 확보

런타임 에러를 타입 에러로 전환하는 것만으로도 개발 경험이 크게 개선됐다. 다음은 HTTP 메서드와 요청/응답 타입까지 결합해볼 예정이다.

TypeScript 4.3 template literal types로 타입 안전성 높이기