티스토리 뷰
TS에서 프로미스는 Promise<결괏값> 타입으로 표시합니다.
const p1 = Promise.resolve(1) //Promise<number>
.then((a) => a + 1) //Promise<number>
.then((a) => a + 1) //Promise<number>
.then((a) => a.toString()); // Promise<string>
//then을 전부 다 실행시킨 최종 결괏값을 p1에 리턴한다.
const p2 = Promise.resolve(2); // Promise<number>
const p3 = new Promise((res, rej) => {
setTimeout(res, 1000);
});
Promise.all([p1, p2, p3]).then((result) => console.log(result));
//결과: ['3',2,undefined], result에 커서를 올려보면 최종 타입을 string number unknown 으로 정확히 추론되어 있음
new Promise의 타입을 보기 위해서 커서를 올렸을 시, es2018로 가면 new 키워드에 대한 타입 명세를 볼 수 없습니다. 이럴 때는 es2015.promise.d.ts에서 찾으면 됩니다.
//lib.es2015.promise.d.ts
new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
- 마지막 p3의 추론 타입은 Promise<unknown>입니다. 그 이유는 value T를 넣어주지 않았기 때문인데요.
- 프로미스의 콜백함수로 들어가는 setTimeout(res, 1000)는 아래와 같은 코드입니다. 아무 인자없이 resolve()를 호출하고 있어서 p3가 Promise<unknown> 인 것입니다.
setTimeout(()=> { res(); }, 1000);
Promise.all 타입 분석
//lib.es2015.promise.d.ts
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;
- [P in keyof T] 에서 T는 위의 예시에서 [p1,p2,p3] 입니다.
- T = [p1,p2,p3] 라고 했을 때 이 배열을 객체로 표현하면 {"0": p1, "1": p2, "2": p3, length: 3} 가 됩니다.
- keyof T = "0" | "1" | "2" | "length" 가 되겠네요. P는 해당 배열의 키가 됩니다.
{"0": p1, "1": p2, "2": p3, length: 3} 같은 모양의 객체는 TS에서 배열로 취급합니다.
이해를 돕기위한 예시를 추가하자면 아래와 같습니다.
const arr = [1, 2, 3] as const;
type Arr = keyof typeof arr; //arr에 as const를 붙여야 readonly [1, 2, 3] 가 나옴
const key: Arr = "length"; // 1 , 2 , 3 이라는 number값이 들어가면 오류가 납니다. key 값은 string이니까
- 만약 as const를 [1,2,3]에 붙이지 않는다면 Arr의 타입은 keyof number[] 가 됩니다.
Promise.all 타입의 명세에 Awaited<T[P]> 는 무엇일까요?
Awaited 타입 분석
Awaited 는 es5.d.ts 명세에 있습니다.
- 여기서 T는 배열이고 P는 해당 배열의 key라는 것을 위에서 알아냈습니다. 배열명[key] 즉, 배열의 "값"들을 await 한다라는 의미가 됩니다.
// es5.d.ts
type Awaited<T> = T extends null | undefined
? T // special case for `null | undefined` when not in `--strictNullChecks` mode
: T extends object & { then(onfulfilled: infer F, ...args: infer _): any } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
? F extends (value: infer V, ...args: infer _) => any // if the argument to `then` is callable, extracts the first argument
? Awaited<V> // recursively unwrap the value
: never // the argument to `then` was not callable
: T; // non-object or non-thenable
- 컨디셔널 타입(조건부 타입)이 3번이나 나왓지만 쫄지말고 주석을 참고하면서 분석하면 됩니다.
- 첫째줄부터 T는 p1,p2,p3라고 했으니 첫째줄의 내용은 무시해도됩니다. (T extends null | undefined 부분)
- 두번째줄은 T가 extends 뒤의 조건을 만족하는 지 묻고있습니다. 객체이고 & { then(onfulfilled: infer F, ...args: infer _):any thenable 객체*인가?
- 세번째줄은 F가 함수꼴이며 V라는 값을 가지고 있는 지에 대해 묻고 있습니다. (value: infer V, ...args: infer _)
- 마지막줄 Awaited<V>는 다시 재귀호출을 하고 있음을 알 수 있습니다. V는 위 예시에서 then 내부에 있는 a라는 value를 가리킵니다.
😎extends와 infer는 세트라는 것을 알고있습니다. infer의 역할이 타입을 추론해주는 것일수도 있지만 어떻게 보면 새로운 타입 변수를 만들어 낸다고 볼 수 있습니다.(만들어낸 타입을 통해서 다시 한번 타입 추론을 하기때문)
thenable 객체
- 맨처음 Promise의 타입은 Promise<T>과 같이 표현한다고 했습니다.
- 하지만, { then(onfulfilled: infer F, ...args: infer _): any } 로 표현해도 TS는 이를 프로미스 타입이라고 추론할 수 있습니다. 이러한 표현에 적용된 TS의 특징은 Duck typing입니다.
- 위의 객체 타입을 직접적으로 표현하면 then메서드를 가지고 있는 객체라는 뜻으로 이 객체는 thenable 하여 프로미스 객체와 동일하게 취급한다는 것입니다.
- 즉, 동일한 일정 프로퍼티를 가지고 있다면 같은 타입으로 치기 때문에 TS가 암시적으로 추론이 가능하게 됩니다.
- 간단히 표현하자면 "오 프로미스도 then을 가지고있는데 프로미스가 가지고있는 then과 모양이 같네? 프로미스 타입으로 치겠음" 이런 느낌이 아닐까 싶습니다.
Duck typing
프로그래밍 분야에서 덕 타이핑은 동적 타이핑의 한 종류로, 객체의 변수 및 메소드의 집합이 객체의 타입을 결정하는 것을 말한다. 클래스 상속이나 인터페이스 구현으로 타입을 구분하는 대신, 덕 타이핑(Duck typing)은 객체가 어떤 타입에 걸맞은 변수와 메소드를 지니면 객체를 해당 타입에 속하는 것으로 간주한다.
TS의 Duck Typing 특성때문에 정의된 타입이 아니더라도 정의된 타입과 같은 Shape를 가지고 있다면 타입체크에서는 에러가 나오지 않는 것입니다.
'Frontend > TypeScript' 카테고리의 다른 글
[TypeScript | styled-components] 스타일드 컴포넌트 사용하기 (0) | 2023.03.05 |
---|---|
[TypeScript] 타입스크립트 자동완성과 DT, TS (0) | 2023.01.14 |
[TypeScript] Required, Record, NonNullable 타입 (0) | 2023.01.02 |
[TypeScript] Utility Types - Partial/ Omit / Pick / Exclude / Extract (0) | 2022.12.30 |
[TypeScript] 타입스크립트 오버로딩, 에러핸들링 (0) | 2022.12.30 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- getServerSideProps
- 타입스크립트 DT
- 항해99프론트
- getStaticPaths
- nvm 설치순서
- && 셸 명령어
- 원티드 FE 프리온보딩 챌린지
- 부트캠프항해
- 형제 요소 선택자
- reactAPI
- fs모듈 넥스트
- 원티드 프리온보딩 프론트엔드 챌린지 3일차
- 프리온보딩 프론트엔드 챌린지 3월
- aspect-ratio
- 프리렌더링확인법
- float 레이아웃
- nvm경로 오류
- 틸드와 캐럿
- 원티드 3월 프론트엔드 챌린지
- D 플래그
- 원티드 프리온보딩 FE 챌린지
- 항해99프론트후기
- ~ ^
- 항해99추천비추천
- 타입스크립트 장점
- grid flex
- Prittier
- is()
- text input pattern
- tilde caret
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함