bh2980.dev

9 - Deep Readonly

  • #Type Challenges
  • #TypeScript

질문

객체의 프로퍼티와 모든 하위 객체를 재귀적으로 읽기 전용으로 설정하는 제네릭 DeepReadonly<T>를 구현하세요.

이 챌린지에서는 타입 파라미터 T를 객체 타입으로 제한하고 있습니다. 객체뿐만 아니라 배열, 함수, 클래스 등 가능한 다양한 형태의 타입 파라미터를 사용하도록 도전해 보세요.

type X = {
  x: {
    a: 1
    b: 'hi'
  }
  y: 'hey'
}

type Expected = {
  readonly x: {
    readonly a: 1
    readonly b: 'hi'
  }
  readonly y: 'hey'
}

type Todo = DeepReadonly<X> // should be same as `Expected`


// !collapse(1:70) collapsed
/* _____________ 테스트 케이스 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<DeepReadonly<X1>, Expected1>>,
  Expect<Equal<DeepReadonly<X2>, Expected2>>,
]

type X1 = {
  a: () => 22
  b: string
  c: {
    d: boolean
    e: {
      g: {
        h: {
          i: true
          j: 'string'
        }
        k: 'hello'
      }
      l: [
        'hi',
        {
          m: ['hey']
        },
      ]
    }
  }
}

type X2 = { a: string } | { b: number }

type Expected1 = {
  readonly a: () => 22
  readonly b: string
  readonly c: {
    readonly d: boolean
    readonly e: {
      readonly g: {
        readonly h: {
          readonly i: true
          readonly j: 'string'
        }
        readonly k: 'hello'
      }
      readonly l: readonly [
        'hi',
        {
          readonly m: readonly ['hey']
        },
      ]
    }
  }
}

type Expected2 = { readonly a: string } | { readonly b: number }

선행 지식

  1. object, Object, {} 타입

    object : 원시 타입을 제외한 모든 객체 타입(함수, 배열 등 포함)

    Object : JS의 Object에 대응하는 매우 넓은 타입.(실무에서 필터로 사용하기엔 비권장)

    {} : nullundefined를 제외한 모든 타입

  2. 배열의 키

    배열도 객체이므로 keyof를 통해 순회 가능하다.

  3. readonly

    any[] extends readonly any[] ? true : false // true

    할당(대입) 가능성 기준으로, readonly 리스트 타입은 “쓰기 불필요”라 요구사항이 약하므로 더 넓다. 따라서 mutable 리스트는 readonly 리스트에 할당 가능하다.