미라클 글쓰기 4일차

easy – Readonly

문제 링크: https://github.com/type-challenges/type-challenges/blob/main/questions/00007-easy-readonly/README.ko.md

T의 모든 프로퍼티를 읽기 전용(재할당 불가)으로 바꾸는 내장 제네릭 Readonly<T>를 이를 사용하지 않고 구현하세요.

예시:

interface Todo {
  title: string
  description: string
}

const todo: MyReadonly<Todo> = {
  title: "Hey",
  description: "foobar"
}

todo.title = "Hello" // Error: cannot reassign a readonly property
todo.description = "barFoo" // Error: cannot reassign a readonly property

처음 풀었던 Pick과 유사한 문제로, Mapped Type의 순회를 익숙하게 하는 문제다.

이 문제를 풀기 위해 알아야 할 사전지식은 다음과 같다.

  • keyof Operator
  • Mapped Type
  • Indexed Access Type
  • readonly Keyword

제네릭 Type T의 모든 프로퍼티를 readonly로 변경하는 문제이므로, 모든 프로퍼티를 순회하면서 프로퍼티를 readonly로 바꾸면 된다.

type MyReadonly<T> = { readonly [k in keyof T]: T[k] }

easy – Awaited

문제 링크: https://github.com/type-challenges/type-challenges/tree/main/questions/00189-easy-awaited

by Maciej Sikora @maciejsikora

도전하기    English 简体中文 日本語

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

예시: 들어 Promise<ExampleType>이 있을 때, ExampleType을 어떻게 얻을 수 있을까요?

type ExampleType = Promise<string>

type Result = MyAwaited<ExampleType> // string
출처: original article by @maciejsikora

compile time에 recursion을 통해 타입을 추론하는 방법을 연습하는 문제로, 이런 방법이 있는 줄은 Type Challenge를 풀어보기 전에는 생각도 못했다.

사전에 알아야 할 지식은 다음과 같다.

  • Conditional Type
  • infer Keyword

Conditional Type은 Ternary(Conditional) Operator를 type 에 사용, 조건에 따라 type을 분기한다.

type A = A extends B  ? C : D;

Conditional Type의 특성에 따라 조건 분기문에 자기 자신의 Type을 넣을 수 있고, 이를 통해 재귀적인 타입 추론(!)이 가능하다.(어떤 방식인지 끝까지 보면 알 수 있다.)


주어진 문제는 Promise로 감싸인 내부의 타입을 compile time에 알아내는 것이므로, 주어진 제네릭 타입 T가 Promise인지 여부를 판별해 보자.
문제를 단계별로 해결하기 위해 일단은 T가 Promise<string> 인 경우만 가정해보면 다음과 같다.

type MyAwaited<T> = T extends Promise<string> ? string : T;

여기서 T가 Promise<number> 인 경우를 추가한다면

type MyAwaited<T> = T extends Promise<string> ?
  string :
  T extends Promise<number> ? 
      number :
      T;

이런 식으로 지저분하게 계속 조건을 늘릴 수도 있지만, 우아하게 infer keyword를 이용해보자.
infer R 을 사용하여 다음과 같이 T 내부에 감싸여 있는 어떤 Type인지 결정되지 않은 Type을 표현할 수 있다.

type MyAwated<T> = T extends Promise<infer R> ? R : T;

가장 까다로운 케이스는 Promise를 Promise로 감싸는 형태다. 몇 겹을 감싸게 될런지 모르기 때문에
다음과 같이 conditional 분기에서 재귀적으로 타입을 추론해보자.

type MyAwaited<T> = T extends Promise<infer R> ?
    R extends Promise<any> ?
        MyAwaited<R> :
        R:
    T;

최종 test case까지 통과하려면 T가 반드시 Promise<?> 이면서 PromiseLike 하여야 하므로,
최종 답안은 다음과 같다.

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

댓글 남기기

인기 검색어

01010011에서 더 알아보기

지금 구독하여 계속 읽고 전체 아카이브에 액세스하세요.

계속 읽기