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 메서드와 요청/응답 타입까지 결합해볼 예정이다.