본문 바로가기
Language/Typescript

타입챌린지 : 1130-ReplaceKeys (medium)

by hsloth 2023. 4. 22.

 

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

 

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



제네릭 인자로 받은 타입의 key값을 바꾸는 타입이다. 솔직히 왜 이런 타입을 만든지는 잘 모르겠다.

 

 

type ReplaceKeys<U, T, Y> = {
  [P in keyof U]: T extends keyof Y ?
  P extends keyof Y ? Y[P] : U[P] : 
  P extends T ? never : U[P];
}


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

type NodeA = {
  type: 'A'
  name: string
  flag: number
}

type NodeB = {
  type: 'B'
  id: number
  flag: number
}

type NodeC = {
  type: 'C'
  name: string
  flag: number
}

type ReplacedNodeA = {
  type: 'A'
  name: number
  flag: string
}

type ReplacedNodeB = {
  type: 'B'
  id: number
  flag: string
}

type ReplacedNodeC = {
  type: 'C'
  name: number
  flag: string
}

type NoNameNodeA = {
  type: 'A'
  flag: number
  name: never
}

type NoNameNodeC = {
  type: 'C'
  flag: number
  name: never
}

type Nodes = NodeA | NodeB | NodeC
type ReplacedNodes = ReplacedNodeA | ReplacedNodeB | ReplacedNodeC
type NodesNoName = NoNameNodeA | NoNameNodeC | NodeB

type cases = [
  Expect<Equal<ReplaceKeys<Nodes, 'name' | 'flag', { name: number; flag: string }>, ReplacedNodes>>,
  Expect<Equal<ReplaceKeys<Nodes, 'name', { aa: number }>, NodesNoName>>,
]

답은 생각보다 간단하다.

[P in keyof U] : 타입 U의 키들을 P라고 정의한다.

T extends keyof Y ? P extends keyof Y ? Y[P] : U[P] : T가 Y의 키값이고, P가 Y의 키값이면, Y[P]를 리턴한다(변화된 타입을 리턴). 만약 P가 Y의 키값이 아니라면 U[P]를 리턴한다(변화되지 않은 값 리턴)

P extends T ? never : U[P] : T가 Y의 키값이 아니고, P가 T와 같다면, never를 리턴한다(두 번째 케이스를 통과하기 위해 설정해주었다) 만약 P와 T가 다르다면 U[P]를 리턴한다. 

 

 

찾아보니 더 쉬운 방법도 있었다..

type ReplaceKeys<U, T, Y> = { 
  [K in keyof U]: K extends T ? K extends keyof Y ? Y[K] : never : U[K] 
}

extends를 적절히 사용해주면 다음과 같이 표현도 가능하다.