TypeScript 5.5의 infer를 이용한 타입 추론 개선
문제 상황
레거시 API 클라이언트 코드를 리팩토링하던 중, 각 엔드포인트마다 수동으로 응답 타입을 정의하는 것이 번거로웠다. 특히 중첩된 데이터 구조에서 특정 필드의 타입만 추출해야 하는 경우가 많았다.
type ApiResponse<T> = {
data: T;
meta: { total: number; page: number };
};
// 매번 이렇게 작성하는 게 번거로웠음
type UserData = ApiResponse<User>['data'];
해결 방법
TypeScript 5.5에서 개선된 infer 키워드를 활용해 유틸리티 타입을 만들었다.
type ExtractData<T> = T extends ApiResponse<infer U> ? U : never;
type ExtractArrayItem<T> = T extends (infer U)[] ? U : never;
// 사용 예시
type UsersResponse = ApiResponse<User[]>;
type UserType = ExtractArrayItem<ExtractData<UsersResponse>>;
이전 버전에서는 조건부 타입과 infer를 조합할 때 타입 추론이 제대로 되지 않는 경우가 있었는데, 5.5에서는 훨씬 안정적이었다.
실전 활용
실제로는 fetch 함수의 반환 타입에서 자동으로 추출하도록 구현했다.
const fetcher = <T>(url: string) =>
fetch(url).then(r => r.json()) as Promise<ApiResponse<T>>;
type InferFetcherData<T> = T extends Promise<ApiResponse<infer U>>
? U
: never;
type UserListData = InferFetcherData<ReturnType<typeof fetcher<User[]>>>;
타입 정의 코드가 약 30% 정도 줄어들었고, API 스펙 변경 시 타입 동기화도 수월해졌다. 다만 과도하게 복잡한 infer 체이닝은 오히려 가독성을 해치므로 적절한 수준에서 사용하는 게 중요하다.