TypeScript 5.5의 infer 제약 조건과 실무 적용
문제 상황
레거시 API 래퍼를 리팩토링하던 중, 응답 데이터의 중첩 구조에서 특정 필드만 추출하는 유틸리티 타입이 필요했다. 기존 방식은 any로 우회하거나 수동으로 타입을 정의해야 했다.
// 기존 방식
type ExtractData<T> = T extends { data: any } ? T['data'] : never;
TypeScript 5.5의 개선점
5.5 버전에서 infer에 제약 조건을 직접 명시할 수 있게 되면서 타입 추론이 훨씬 정교해졌다.
type ExtractData<T> = T extends { data: infer D extends Record<string, unknown> }
? D
: never;
type ApiResponse = {
data: { userId: number; name: string };
meta: { timestamp: number };
};
type UserData = ExtractData<ApiResponse>;
// { userId: number; name: string }
실무 적용
실제 프로젝트의 API 클라이언트에 적용했다. 페이지네이션, 에러 핸들링 등 공통 응답 구조에서 실제 데이터만 추출하는 타입을 작성했다.
type UnwrapResponse<T> =
T extends { success: true; data: infer D extends object }
? D
: T extends { success: false; error: infer E }
? never
: T;
const response = await fetchUser();
type User = UnwrapResponse<typeof response>;
제네릭 중첩이 깊어질수록 타입 추론 성능이 눈에 띄게 개선되었다. 빌드 시간도 약간 단축되었다.
결론
infer 제약 조건은 복잡한 유틸리티 타입 작성 시 가독성과 안정성을 동시에 높여준다. 기존 코드베이스에서 any를 사용하던 부분을 점진적으로 교체하는 중이다.