기본 패턴
ts
async function fetchUser(id: string): Promise<User> {
const res = await api.get(`/users/${id}`);
return res.data;
}
type UserResult = Awaited<ReturnType<typeof fetchUser>>;설명
async함수는 값을 직접 반환하는 것처럼 보여도 타입 수준에서는 항상Promise<...>를 반환합니다. 그래서 비동기 함수의 핵심 타입은 "최종 결과 타입"이 아니라 "Promise 안에 무엇이 들어 있나"입니다.await는 Promise를 풀어 안쪽 값을 꺼내는 문법이고, TypeScript는 이 과정을 타입 수준에서도 추적합니다. 즉await promiseOfUser를 하면 결과 타입은User가 됩니다.Awaited<T>는 이런 언랩 과정을 타입으로 표현하는 유틸리티입니다. 중첩 Promise나PromiseLike가 섞인 타입을 다룰 때 특히 유용합니다.- 실무에서는
Promise<T>를 명시하는 것만큼, API helper와 wrapper 함수의 반환 타입을 중복 없이 재사용하는 일이 중요합니다. 이때ReturnType과Awaited조합이 자주 등장합니다. - 결국 TypeScript의 비동기 타입 설계는 "지금 이 값이 Promise 자체인가, 이미 풀린 결과인가"를 명확히 구분하는 습관에서 시작합니다.
빠른 정리
| 표현 | 의미 |
|---|---|
async function fn(): Promise<T> | 비동기 함수가 최종적으로 T를 돌려줌 |
await promise | Promise 안쪽 값을 꺼냄 |
Promise<T> | 아직 도착하지 않은 T |
Awaited<T> | Promise 구조를 한 단계 이상 풀어 최종 값 타입 추출 |
| 실전 조합 | Awaited<ReturnType<typeof fn>> |
주의할 점
Promise<User>와 User를 섞어 생각하면 타입이 바로 흔들립니다. 함수 시그니처를 볼 때는
"이 함수가 값을 반환하는가, Promise를 반환하는가"를 먼저 분리해서 읽는 습관이 중요합니다.
참고 링크
2 sources