Promise와 같은 타입에 감싸인 타입이 있을 때, 안에 감싸인 타입이 무엇인지 어떻게 알 수 있을까요?
예시:Promise<ExampleType>이 있을 때, ExampleType을 어떻게 얻을 수 있을까요?
type MyAwaited<T extends PromiseLike<any>> =
T extends PromiseLike<infer K>?
(K extends PromiseLike<any>?
(MyAwaited<K>)
:(K)
)
:(never);
나는 conditional type이 여러 개 올 경우 디버깅을 위해 괄호를 사용하는 편이다.
또, 중첩된 경우 참과 거짓에 들어갈 곳에 다시 괄호를 사용한다
조건?
(참)
:(거짓)
infer 키워드를 통해 PromiseLike의 제네릭을 추론 후,
그 제네릭이 PromiseLike에 호환 가능하면 재귀적으로 타입을 확인하고,
그렇지 않으면 추론된 타입이 결과 타입이 된다.
{ then: (onfulfilled: (arg: number) => any) => any }과 같은 반례 해결을 위해
받을 수 있는 타입을 Promise가 아닌 PromiseLike로 값을 받았다
PromiseLike타입은
index 접근이 가능하고,length 프로퍼티를 갖는 ArrayLike 개념과 유사하다.
Promise 타입과 유사한 then이 구현되어 있는 타입이면 PromiseLike로 보는 듯 하다
// lib.es5.d.ts
interface PromiseLike<T> {
then<TResult1 = T, TResult2 = never>(
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>)| undefined | null,
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
): PromiseLike<TResult1 | TResult2>;
}
다른 블로그를 참고해서 이 타입의 기원을 알 수 있었다.
Promise가 공식 기능으로 채택되기 전, 다양한 라이브러리들이 존재했는데, 그 라이브러리들과의 호환을 위해 이런 타입이 생겨난 것 같다.
(그래서 ArrayLike는 공식 문서가 있지만, PromiseLike라는 개념은 없는 듯 하다)
PromiseLike에 대응하기 위해 custom type을 만든 사람도 있었고,
문제에 PromiseLike를 대응하지 않은 답안도 존재했다.(아마 이전에는 PromiseLike 대응이 필요 없었을 듯)
https://yceffort.kr/2021/11/array-arraylike-promise-promiselike