← 전체 글로 돌아가기

API

TypeScript 타입을 API 스키마와 맞추는 방법

API 응답 타입이 실제 데이터와 안 맞으면 런타임에 버그가 터진다. 처음부터 맞추는 게 핵심이다.

TypeScript를 쓸 때 가장 흔한 실수는 타입 정의와 실제 API 응답이 어긋나는 거다. 개발할 땐 문제가 없다가 운영 데이터를 만나면 예상 밖의 필드가 있거나 타입이 다를 수 있다.

먼저 실제 API 응답 확인하기

타입을 정의하기 전에 API가 실제로 뭘 반환하는지 봐야 한다.

curl -s 'https://api.example.com/items?page=1' | jq '.'

jq로 보면 필드 구조와 각 값의 타입이 한눈에 들어온다. 특히 null 가능성, 배열인지 객체인지, 문자열인지 숫자인지 꼭 확인한다.

타입 정의 체크리스트

실제 응답을 본 뒤에 타입을 정의한다:

  • 모든 필드를 포함했는가
  • 옵셔널(?)과 필수 필드를 올바르게 구분했는가
  • null 가능한 필드는 | null을 붙였는가
  • 날짜 문자열은 string 아니면 Date로 할 건가
  • 열거형은 리터럴 타입 유니온으로 정의했는가
type Item = {
  id: string;
  name: string;
  price: number;
  tags: string[];
  createdAt: string; // ISO 8601
  updatedAt?: string;
  deletedAt: string | null;
};

런타임에 타입 검증하기

TypeScript는 컴파일할 때만 타입을 확인한다. 런타임에는 아무것도 확인 안 하기 때문에 서버에서 예상 밖의 데이터가 올 수 있다. 실제 사용하는 곳에서 타입 가드를 넣으면 좋다.

function isItem(obj: unknown): obj is Item {
  return (
    typeof obj === 'object' &&
    obj !== null &&
    'id' in obj &&
    'name' in obj &&
    'price' in obj
  );
}

const response = await fetch('/api/items');
const data = await response.json();

if (isItem(data)) {
  // data의 타입이 Item임을 보장
  console.log(data.name);
}

API 변경에 대비하기

API가 업데이트되면서 새 필드가 추가되거나 사라질 수 있다. 타입을 정의할 때부터 앞으로의 변화를 고려하면 유지보수가 쉬워진다.

// 나쁜 예: 빠진 필드 발견 시 모든 코드에서 에러
type Item = {
  id: string;
  name: string;
};

// 좋은 예: 알 수 없는 필드는 무시
type Item = {
  id: string;
  name: string;
  [key: string]: unknown;
};

타입과 API 응답을 맞추는 건 시간이 걸리지만, 나중의 디버깅 시간을 크게 줄인다.