iamkanguk.dev

[타입챌린지-MEDIUM] 9: Deep Readonly 본문

Type Challenge

[타입챌린지-MEDIUM] 9: Deep Readonly

iamkanguk 2024. 4. 4. 22:11

문제

https://github.com/type-challenges/type-challenges/blob/main/questions/00009-medium-deep-readonly/README.md

 

type-challenges/questions/00009-medium-deep-readonly/README.md at main · type-challenges/type-challenges

Collection of TypeScript type challenges with online judge - type-challenges/type-challenges

github.com

 

풀이

/* _____________ 여기에 코드 입력 _____________ */

type DeepReadonly<T> = {
  readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>
}


/* _____________ 테스트 케이스 _____________ */
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 }

풀이 해설

이 문제의 핵심은 재귀적으로 구현을 해야한다는 점이다. depth 별로 확인하면서 readonly를 모두 추가해주어야 한다.

  • readonly [P in keyof T]: 앞에 readonly를 붙여줄건데 T의 key list를 순회한다. 순회할 때 P로 변수지정을 해준다.
  • keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>
    • keyof T[P]: 만약에 특정 key에 대해 value가 또 객체의 구조일 경우를 생각해서 keyof를 붙여주었다.
    • extends never ? T[P] : DeepReadonly<T[P]>: T[P]의 key들을 봤는데 key가 없는 경우(특정 key에 대한 value가 객체인 구조가 아닌경우)는 T[P] 그대로를, 그렇지 않은 경우에는 해당 value(객체)를 가지고 다시 DeepReadonly를 적용해준다.

 

재귀를 어떻게 사용해야하지? 라고 생각을 할 수 있으면 충분히 풀 수 있는 문제였던 것 같다.