TypeScript의 조건부 타입으로 API 응답 타입 자동 추론하기
문제 상황
사용자 정보를 조회하는 API에서 includeDetail 파라미터에 따라 응답 형태가 달랐다. false일 때는 기본 정보만, true일 때는 상세 정보까지 포함되는 구조였다.
기존에는 union 타입으로 처리했지만, 매번 타입 가드를 작성해야 했고 실수의 여지가 있었다.
interface BasicUser {
id: string;
name: string;
}
interface DetailedUser extends BasicUser {
email: string;
phone: string;
address: string;
}
type UserResponse = BasicUser | DetailedUser;
조건부 타입 적용
TypeScript의 조건부 타입을 활용해 파라미터 값에 따라 반환 타입을 자동으로 추론하도록 개선했다.
interface FetchUserOptions {
includeDetail?: boolean;
}
type UserResult<T extends FetchUserOptions> =
T['includeDetail'] extends true ? DetailedUser : BasicUser;
function fetchUser<T extends FetchUserOptions>(
id: string,
options: T
): Promise<UserResult<T>> {
// 구현
return fetch(`/api/users/${id}`, {
params: options
}).then(res => res.json());
}
사용 예시
// 자동으로 BasicUser 타입으로 추론
const basicUser = await fetchUser('123', { includeDetail: false });
console.log(basicUser.name); // OK
console.log(basicUser.email); // 타입 에러
// 자동으로 DetailedUser 타입으로 추론
const detailedUser = await fetchUser('123', { includeDetail: true });
console.log(detailedUser.email); // OK
결과
타입 가드 없이도 컴파일 타임에 안전하게 타입을 추론할 수 있게 되었다. 비슷한 패턴을 가진 다른 API에도 적용 중이다.
조건부 타입은 처음에는 복잡해 보이지만, 이런 케이스에서는 매우 유용하다.