본문 바로가기
Books/타입스크립트 교과서

타입스크립트 교과서: 3-10 Awaited, Promise

by SeungYn 2023. 12. 1.
타입스크립트 교과서가 나왔길래 보는 중. 어려운 부분이 있어서 작성
Awaited에 대한 이야기다. 이걸 직접 사용해 본적은 없는데 가끔 라이브러리를 찾아보면 이런게 써져 있음
Awaited에 대해 알아보자

1. 프로미스는 기본적으로 Awaited 타입이 붙여짐

2. await 키워드를 붙이면 자동으로 Awaited로 감싸짐

const str1 = Promise.resolve('promise');
// type str1 = Promise<Awaited<string>>
const str2 = await Promise.resolve('promise');
// type str2 = Awaited<Promise<Awaited<string>>>

3. Awaited 분석 규칙

 규칙 1 Awaited<객체가 아닌 값> === 객체가 아닌 값
 규칙 2 Awaited<Promise<T>> === Awaited<T>
 규칙은 아래를 읽고 코드를 직접 분석하다 보면 알게됨

Awaited 타입

  type Awaited<T> = T extends null | undefined
  ? T // null, undefined이면 그대로 반환
  : T extends object & { then(onfulfilled: infer F, ...args: infer _): any } // then을 상속한 객체이면 then의 콜백함수를 F로 추론
  ? F extends (value: infer V, ...args: infer _) => any // F로 추론한 콜백함수의 인자를 V로 추론
  ? Awaited<V> // Awaited<V>로 재귀적 추론
  : never // the argument to `then` was not callable
  : T; // then이 있는 Object(promise)가 아니면 값을 그대로 반환

3.1 설명

// 첫 번째 삼항 연산자
// 첫 번째 삼항 연산자를 보면 null이나 undefined일 경우 그대로 반환
// 아닐 경우 두 번쨰 삼항 연산자로 넘어간다.
type Awaited<T> = T extends null | undefined ? T : 두 번쨰 삼항 연사자

// 두 번째 삼항 연산자
// 첫 번째 삼항 연자자에서 넘어온 T 가 Object이며 then 메서드를 상속 하면 then 메서드의 1번째 골백 함수를 F로 추론
// 참이면 세 번째 삼항 연산자로 넘어간다.
// 아닐 경우 T를 반환
type Awaited<T>  = T extends object & { then(onfulfilled: infer F, ...args: infer _): any } 
    ? 세 번째 삼항 연산자
    ? T

// 세 번째 삼항 연산자
// 두 번째 삼항 연산자에서 넘어온 추론된 F가 인자가 있는 함수이면 첫번쨰 파라미터를 V로 추론
// 참일 경우 Awaited<V>로 재귀적 추론
// 아닐 경우 never
type Awaited<T>  = F extends (value: infer V, ...args: infer _) => any
    ? Awaited<V> // Awaited<V>로 재귀적 추론
    : never // the argument to `then` was not callable

3.2 예시

const result2 = await Promise.resolve(123).then((data) => {
  return data;
});

// type result2 = number;
여기서 result2는 number로 추론이 됨.
1. Promise.resolve(123) 가 두번 째 삼항연산자에서 참으로 되기 떄문
2. 이유는 Promise 인스턴스이며 then을 상속하기 때문
3. 2번쨰 삼항 연산자에서 then의 콜백 함수가 F로 추론되어 3번째 삼항 연산자로 넘어가고
4. 3번째 삼항 연산자에서 F가 제시한 함수 형태를 띄우고 있으므로 1번째 파라미터를 V로 추론하기 떄문 여기서 V는 number인 것을 알 수 있음
5. 그후 추론된 V로 Awaited<V>를 재귀적으로 추론함.
6. Awaited<V>는 null이나 undefined가 아니며 Promise 인스턴스도 아니기 때문에 최종적으로 number을 반환

천천히 읽다 보면 누구나 이해 가능!