TypeScript 4.4 템플릿 리터럴 타입으로 API 라우팅 타입 안전하게 관리하기
문제 상황
프로젝트에서 REST API 엔드포인트를 문자열로 관리하다 보니 경로 오타로 인한 404 에러가 종종 발생했다. /api/user/${userId}/posts와 같은 동적 경로에서 특히 실수가 잦았다.
// 기존 방식 - 타입 체크 없음
const endpoint = `/api/user/${userId}/post`; // posts가 아닌 post로 오타
fetch(endpoint);
TypeScript 4.4 템플릿 리터럴 타입
8월에 릴리즈된 TypeScript 4.4의 템플릿 리터럴 타입 개선을 활용해 타입 안전한 API 경로 빌더를 만들었다.
type ApiPath =
| '/api/users'
| '/api/posts'
| `/api/users/${string}`
| `/api/users/${string}/posts`;
function apiCall<T extends ApiPath>(path: T) {
return fetch(path);
}
// 타입 체크 통과
apiCall(`/api/users/${userId}/posts`);
// 타입 에러 발생
apiCall(`/api/user/${userId}/post`);
더 나아가기
경로 파라미터까지 타입으로 추출할 수 있다.
type ExtractParams<T extends string> =
T extends `${infer _Start}/:${infer Param}/${infer Rest}`
? Param | ExtractParams<Rest>
: T extends `${infer _Start}/:${infer Param}`
? Param
: never;
type UserPostPath = '/api/users/:userId/posts/:postId';
type Params = ExtractParams<UserPostPath>; // 'userId' | 'postId'
결과
타입 체크 덕분에 IDE에서 자동완성도 잘 동작하고, 배포 전에 경로 오타를 잡아낼 수 있게 되었다. 다만 모든 경로를 타입으로 정의해야 하는 보일러플레이트는 여전히 남아있어, 다음에는 OpenAPI 스펙에서 타입을 자동 생성하는 방향을 고려해볼 예정이다.