본문 바로가기
Language/Typescript

타입챌린지 : 2759-RequiredByKeys (medium)

by hsloth 2023. 5. 14.

 

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

 

https://github.com/type-challenges/type-challenges/blob/main/questions/02759-medium-requiredbykeys/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

 

PartialByKeys와는 반대로, K라는 이름을 가진 optional인 속성을 required로 바꾸어서 리턴하는 타입이다.

 

 

처음에 생각한 답

type IntersectionToObj<T> = {
  [P in keyof T]: T[P]
}

type RequiredByKeys<T, K extends keyof T> = IntersectionToObj<{
  K: T[K]
} & {
  [P in keyof T as P extends K ? never : P]: T[P]
}>

인터섹션타입을 obj로 바꾸는 타입인 IntersectionToObj를 이용해서 K만 따로 객체로 만들고, 키 값이 K인 것을 제외한 나머지는 그대로 optional로 해서 리턴하는 타입을 만들었다.

하지만, 결과가 key값: string 이런식으로 나와야하는데, 계속 K: string | undefined 이런식으로 나와서 에러가 떴다.

그리고 자꾸 쓸데없이 value타입 뒤에 undefined가 붙는다... 이게 왜 붙는지 모르겠다.

 

type RequiredByKeys<T, K extends keyof T> = T[K] extends undefined | infer F ? IntersectionToObj<{
  [P in K]: F
} & {
  [P in keyof T as P extends K ? never : P]: T[P]
}> : never

이것은 두 번째 답이다. (오답)

T[K]가 undefined를 상속한다면 undefined를 제외한 F를 리턴하도록 만들어봤는데... K에 유니온타입이 들어가면, F에도 똑같이 유니온 타입이 들어가버린다 ㅋㅋ

 

결국.. 이것저것 시도해봤는데 잘 되지 않아서 다른 분들의 답을 보았다....

type RequiredByKeys<T , K extends keyof T = keyof T> = Omit<
	T & Required<Pick<T,K & keyof T>>, never>

Omit을 이용해 Intersection을 객체로 바꾸어주고,

Pick<T, K & keyof T> : T에서 키 값 K를 가진 속성만 뽑아서 (A)

T & Required<A> : 뽑은 속성을 Required로 바꾸어주고 T와 Intersection을 한다.

 

또 다른 답이다.

type RequiredByKeys<T, K extends keyof T = keyof T> = {
  [P in keyof T as P extends K ? never : P]: T[P]
} & {
  [P in keyof T as P extends K ? P : never]-?: T[P]
} extends infer I
  ? { [P in keyof I]: I[P] }
  : never

해당 코드를 통해 두 가지를 알 수 있었다.

첫 째는 [P]-?: T[P] 를 통해 optional(partial)을 해제할 수 있다는 것이었고,

둘 째는 {intersection type} extends infer I ? { [P in keyof I]: I[P] } 를 통해 intersection type을 obj로 바꿀 수 있다는 점이었다.