TypeScript 4.4 Template Literal Type으로 타입 안전한 라우팅 구현

문제 상황

사내 대시보드 프로젝트에서 라우팅 경로를 상수로 관리하고 있었다. 하지만 개발자들이 직접 문자열을 입력하는 경우가 많아 오타로 인한 404 에러가 자주 발생했다.

// 기존 방식
const ROUTES = {
  USER_DETAIL: '/users/:id',
  POST_EDIT: '/posts/:postId/edit'
};

// 사용 시
router.push('/users/123');  // 오타 가능성

Template Literal Type 활용

TypeScript 4.4에서 강화된 Template Literal Type을 사용해 경로 파라미터까지 타입 체킹이 가능하도록 개선했다.

type Route = '/users/:id' | '/posts/:postId/edit' | '/dashboard';
type ExtractParams<T extends string> = 
  T extends `${infer _Start}:${infer Param}/${infer Rest}`
    ? { [K in Param | keyof ExtractParams<`/${Rest}`>]: string }
    : T extends `${infer _Start}:${infer Param}`
    ? { [K in Param]: string }
    : {};

function navigate<T extends Route>(
  route: T,
  params: ExtractParams<T>
) {
  let path = route as string;
  Object.entries(params).forEach(([key, value]) => {
    path = path.replace(`:${key}`, value);
  });
  return path;
}

// 타입 안전한 사용
navigate('/users/:id', { id: '123' });  // OK
navigate('/users/:id', { userId: '123' });  // 컴파일 에러

결과

라우팅 관련 런타임 에러가 80% 이상 감소했다. IDE 자동완성도 동작해서 개발 경험도 개선됐다. 다만 타입 추론이 복잡해져 컴파일 속도가 약간 느려진 점은 아쉬웠다.

프로덕션 배포 후 2주간 라우팅 관련 버그 리포트가 없었다. 타입 시스템을 제대로 활용하면 런타임 안전성을 크게 높일 수 있다는 걸 다시 확인했다.

TypeScript 4.4 Template Literal Type으로 타입 안전한 라우팅 구현