본문 바로가기
Language/Typescript

타입챌린지 : 645-Diff (medium)

by hsloth 2023. 4. 17.

 

이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다.

 

https://github.com/type-challenges/type-challenges/blob/main/questions/00645-medium-diff/README.md

 

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

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

github.com

 

제네릭 O와 O1를 인자로 받아, 두 객체의 공통된 속성을 제외한 나머지 속성을 리턴하는 타입이다.

 

잘 모르겠다면, 다음 챌린지를 참고하자.

https://suloth.tistory.com/73?category=1092932 

 

타입챌린지 : 599-Merge (medium)

이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다. https://github.com/type-challenges/type-challenges/blob/main/questions/00599-medium-merge/READM

suloth.tistory.com

 

위의 포스팅을 보았다면, 이 문제가 생각보다 쉽게 느껴질 것이다.

// 1번째 답
type Diff<O, O1> = {
  [P in keyof O | keyof O1 as P extends keyof (O | O1) ? never : P]: 
  P extends keyof O ? O[P] : P extends keyof O1 ? O1[P] : never;
}

// 2번째 답
type Diff<O, O1> = {
  [P in keyof (O & O1) as P extends keyof (O | O1) ? never : P]: (O & O1)[P]
}


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

type Foo = {
  name: string
  age: string
}
type Bar = {
  name: string
  age: string
  gender: number
}
type Coo = {
  name: string
  gender: number
}

type cases = [
  Expect<Equal<Diff<Foo, Bar>, { gender: number }>>,
  Expect<Equal<Diff<Bar, Foo>, { gender: number }>>,
  Expect<Equal<Diff<Foo, Coo>, { age: string; gender: number }>>,
  Expect<Equal<Diff<Coo, Foo>, { age: string; gender: number }>>,
]

1번째 답은... 2번째 답의 열화 버전이니 2번째 답만 해설하겠다.

[P in keyof (O & O1) as P extends keyof (O | O1) ? never : P] : (O & O1)은 O와 O1의 속성 모두를 가지고 있는 타입이다. 따라서 해당 타입의 key값을 P라고 한다. 그런데, P가 (O | O1)의 키이면, never를 리턴하여 key값을 리턴하지 않고, 만약 아니라면 P를 리턴하여 키 값을 나오게한다. 여기서 (O | O1)은 O와 O1 속성의 공통된 속성만을 가지므로 겹치는 속성을 제외할 수 있다.

(O & O1)[P] : 그리고 key값들의 타입은 (O & O1)타입에 있을테니, (O & O1)[P] 로 지정해준다.

 

keyof (O | O1) 대신, keyof O & keyof O1 과 같이 문자열을 연산하여 사용하여도 됩니다. 자세한 설명은 위의 Merge 포스팅에 맨아래 부분에 나와있습니다.

type Diff<O, O1> = {
  [P in keyof (O & O1) as P extends keyof O & keyof O1 ? never : P]: (O & O1)[P]
}