Type challenges 3

최정은·1일 전

type-challenges

목록 보기
3/3

Awaited

Promise와 같은 타입에 감싸인 타입이 있을 때, 안에 감싸인 타입이 무엇인지 어떻게 알 수 있을까요?

type ExampleType = Promise<string>

type Result = MyAwaited<ExampleType> // string

정답

type MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U> ? U extends PromiseLike<any> ? MyAwaited<U> : U : never;
  1. PromiseLike

    Promise뿐만 아니라 then을 가진 커스텀 객체나 구형 라이브러리의 Promise까지 모두 포함.

  2. MyAwaited<U>
    만약 T가 Promise<Promise<string|number>> 일 경우를 대비하여 만약 U가 PromiseLike라면 재귀로 한 번 더 검증을 한다.

IF

조건 C, 참일 때 반환하는 타입 T, 거짓일 때 반환하는 타입 F를 받는 타입 If를 구현하세요. C는 true 또는 false이고, T와 F는 아무 타입입니다.

type A = If<true, 'a', 'b'>  // expected to be 'a'
type B = If<false, 'a', 'b'> // expected to be 'b'

정답

type If<C extends boolean, T, F> = C extends true ? T : F;

Concat

JavaScript의 Array.concat 함수를 타입 시스템에서 구현하세요. 타입은 두 인수를 받고, 인수를 왼쪽부터 concat한 새로운 배열을 반환해야 합니다.

type Result = Concat<[1], [2]> // expected to be [1, 2]

정답

type Concat<T extends readonly any[], U extends readonly any[]> = [...T, ...U]; 

타입스크립트에서도 타입에 스프레드 연산자 가능! 정확하겐 Variadic Tuple Types (가변 튜플 타입) 을 사용한다고 함.

Push

Array.push의 제네릭 버전을 구현하세요.

type Result = Push<[1, 2], '3'> // [1, 2, '3']

정답

type Push<T extends readonly any[], U> = [...T, U];

다른사람 풀이

type Push<T extends readonly unknown[], U> = [...T, U];

나는 any를 썼고 다른 사람은 unknown을 썼다.

이 둘의 큰 차이는 뭘까?

  1. 타입스크립트 컴파일러에서

    any: 타입 검사를 무시함. 어떤 타입이 들어와도 상관 안함. ⇒ 그래서 런타임 에러가 발생할 수 있음.

    unknown: any와 같이 모든 타입을 받을 수 있다. 하지만 쓰려면 반드시 타입 확인이 필요하다.

  2. 타입 오염

    제네릭이나 교차 타입(&)에서 any는 다른 타입을 덮어쓴다.

    type T1 = any & string;     // 결과: any (string이 잡아먹힘)
    type T2 = unknown & string; // 결과: string (string이 살아남음)

any보다 unknown이 안전하기 때문에 unknown을 쓰는걸 추천한다고 함.

0개의 댓글