TypeScript 4.4 템플릿 리터럴 타입으로 API 엔드포인트 타입 안전하게 관리하기
문제 상황
회사 프로젝트에서 API 엔드포인트를 관리하는 유틸 함수를 만들었는데, 문자열 기반이라 오타가 자주 발생했다.
const getApiUrl = (resource: string, id?: string) => {
return id ? `/api/${resource}/${id}` : `/api/${resource}`;
};
// 사용
fetch(getApiUrl('usres', '123')); // 오타인데 컴파일 에러 없음
해결 방법
TypeScript 4.4부터 지원하는 템플릿 리터럴 타입을 활용했다.
type Resource = 'users' | 'posts' | 'comments';
type ApiEndpoint<T extends Resource> = `/api/${T}` | `/api/${T}/${string}`;
const getApiUrl = <T extends Resource>(resource: T, id?: string): ApiEndpoint<T> => {
return (id ? `/api/${resource}/${id}` : `/api/${resource}`) as ApiEndpoint<T>;
};
// 타입 안전성 확보
const url: ApiEndpoint<'users'> = getApiUrl('users', '123'); // OK
const wrongUrl = getApiUrl('usres', '123'); // 컴파일 에러!
추가 개선
HTTP 메서드까지 타입으로 관리하는 방식으로 확장했다.
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiConfig<T extends Resource> = {
method: HttpMethod;
endpoint: ApiEndpoint<T>;
};
const createApiConfig = <T extends Resource>(
method: HttpMethod,
resource: T,
id?: string
): ApiConfig<T> => ({
method,
endpoint: getApiUrl(resource, id),
});
결과
오타로 인한 API 호출 실패가 배포 전에 잡히기 시작했다. IDE의 자동완성도 정확해져서 개발 속도도 향상됐다. 템플릿 리터럴 타입은 생각보다 실용적이었다.