View on GitHub: https://tsch.js.org/8 */ /* _____________ Your Code Here _____________ */ type MyReadonly2 = any /* _____________ Test Cases _____________ */ import { Equal, Expec"> View on GitHub: https://tsch.js.org/8 */ /* _____________ Your Code Here _____________ */ type MyReadonly2 = any /* _____________ Test Cases _____________ */ import { Equal, Expec"> View on GitHub: https://tsch.js.org/8 */ /* _____________ Your Code Here _____________ */ type MyReadonly2 = any /* _____________ Test Cases _____________ */ import { Equal, Expec">
/*
  8 - Readonly 2
  -------
  by Anthony Fu (@antfu) #medium #readonly #object-keys
  
  ### Question
  
  Implement a generic `MyReadonly2<T, K>` which takes two type argument `T` and `K`.
  
  `K` specify the set of properties if `T` that should set to Readonly. When `K` is not provided, it should make all properties readonly just like the normal `Readonly<T>`.
  
  For example
  
  ```ts
  interface Todo {
    title: string
    description: string
    completed: boolean
  }
  
  const todo: MyReadonly2<Todo, 'title' | 'description'> = {
    title: "Hey",
    description: "foobar",
    completed: false,
  }
  
  todo.title = "Hello" // Error: cannot reassign a readonly property
  todo.description = "barFoo" // Error: cannot reassign a readonly property
  todo.completed = true // OK

View on GitHub: https://tsch.js.org/8 */

/* _____________ Your Code Here _____________ */

type MyReadonly2<T, K> = any

/* _____________ Test Cases _____________ */ import { Equal, Expect } from '@type-challenges/utils'

type cases = [ Expect<Equal<MyReadonly2<Todo1>, Readonly<Todo1>>>, Expect<Equal<MyReadonly2<Todo1, 'title' | 'description'>, Expected>>, ]

interface Todo1 { title: string description?: string completed: boolean }

interface Expected { readonly title: string readonly description?: string completed: boolean }

/* _____________ Further Steps _____________ / /

Share your solutions: https://tsch.js.org/8/answer View solutions: https://tsch.js.org/8/solutions More Challenges: https://tsch.js.org */


두번째 제네릭으로 전달 받은 키만 readonly로 만들어야 한다.

교차 타입을 사용해야 될 것 같긴 했다. 그런데 그랬을 때 동작은 되지만 타입이 제대로 인식이 안되어서 Combine 이라는 타입을 만들어서 merge 하는 느낌으로 만들어 주었다. 

```tsx
type Combine<T> = {
  [k in keyof T]: T[k]
}

type MyReadonly2<T, K extends keyof T> = Combine<T & {  
  readonly [S in K]: T[S]
}>

그런데 그랫더니 두번째 제네릭 파라미터를 전달하지 않는 경우의 테스트가 성공되지 않았다. 그래서 처음에는 조건부로 타입을 리턴하려 했는데 잘 안되서 고민하다가 K 의 기본값을 추가했다!!

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

type MyReadonly2<T, K extends keyof T = keyof T> = Combine<T & {  
  readonly [S in K]: T[S]
}>

어느날 다른 답

type MyReadonly2<T, K extends keyof T = keyof T> = {
  readonly [key in K]: T[key];
} & {
  [key in Exclude<keyof T, K>]: T[key]
}