TypeScript로 API 데이터 가져오기: 타입 어설션 사용
Source: Dev.to
문제 이해
JavaScript에서 API 데이터를 가져올 때 보통 다음과 같이 작성합니다:
const response = await fetch("https://randomuser.me/api/?results=3");
const data = await response.json();
console.log(data);
JavaScript는 타입을 신경 쓰지 않기 때문에, API 구조나 필드가 바뀌어도 코드는 그대로 실행됩니다.
TypeScript에서는 response.json()이 any(또는 설정에 따라 unknown)를 반환합니다. TypeScript는 데이터의 형태를 알지 못하므로, 중첩된 속성에 안전하게 접근할 수 없으며 오류가 발생할 위험이 있습니다. 여기서 타입 어설션이 필요합니다.
![RandomUser API가 반환하는 JSON 구조]
![EscuelaJS Products API가 반환하는 JSON 구조]
TypeScript 타입 어설션 사용하기
타입 어설션은 TypeScript에게 “이 데이터의 구조를 나는 더 잘 안다”라고 알려주는 방법입니다.
![타입 어설션 예시]
예시
const data = await response.json();
const users = data as unknown as {
results: {
name: { first: string; last: string };
email: string;
picture: { large: string };
}[];
};
response.json()이후data는unknown타입입니다.as unknown as { … }는 TypeScript에게 “data를results배열을 가지고, 그 안에 정확히 이 구조가 있는 객체로 취급해라”라고 알려줍니다.
이렇게 하면 TypeScript가 오류를 표시하지 않으면서 results[0].name.first와 같은 중첩 속성에 안전하게 접근할 수 있습니다. TypeScript가 너무 보수적으로 직접 변환을 거부할 때는 이중 어설션(as unknown as)이 필요할 수 있습니다.
![이중 어설션 설명]
API 데이터를 자체 타입으로 매핑하기
타입을 어설션한 뒤에도 전체 중첩 API 구조를 앱 전역에 노출하면 번거롭습니다. 대신 데이터를 더 간단한 내부 타입으로 변환합니다:
export type User = {
name: string;
email: string;
picture: string;
};
return users.results.map(u => ({
name: `${u.name.first} ${u.name.last}`,
email: u.email,
picture: u.picture.large,
}));
이제 애플리케이션의 나머지 부분은 깔끔하고 예측 가능한 User[] 배열을 사용하게 되며, 올바른 타입 지정과 자동 완성 지원을 받을 수 있습니다.
왜 중요한가?
이 과정을 통해 TypeScript가 다음과 같은 여러 면에서 도움이 된다는 것을 깨달았습니다:
- 런타임 충돌 방지 – TS는 코드가 실행되기 전에 실수를 잡아줍니다.
- 자동 완성 / IntelliSense – 오타를 줄이고 더 빠르게 코딩할 수 있습니다.
- 자체 문서화 코드 – 타입은 코드를 읽는 사람에게 데이터 형태를 정확히 알려줍니다.
- 안전한 리팩터링 – 필드 이름이 바뀌거나 API가 변경되면 TS가 경고해 줍니다.
사용자나 제품을 가져오는 작은 실험이라도, 실제 프로젝트에서 타입이 적용된 비동기 흐름을 배우는 데 큰 도움이 됩니다.
핵심 포인트
- TypeScript는 API 데이터를 자동으로 알지 못합니다; 우리는 타입이나 타입 어설션을 통해 알려줘야 합니다.
- API 데이터를 우리만의 타입으로 매핑하면 앱이 더 안전하고 다루기 쉬워집니다.