본문 바로가기

TypeScript

[Type-Challenges] easy - Pick

트리스티가 Nest Js를 공부하며 남긴 기록입니다. 틀린 내용은 언제든지 말씀해주세요 ~!

 

👾 Type-Challenges 

 

타입 챌린지 프로젝트는 타입 시스템이 어떻게 작동하는지 이해하고, 문제의 유틸리티를 작성해보며 타입 스크립트의 빅-꿀잼 경험을 목표로 하고 있습니다. 

 

한국어로도 제공하고 있으니 타입 스크립트를 공부한다면 열심히 풀어봅시다!!! 

 

 

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

 

 

 

 

🤔 문제 설명 

 T에서 K 프로퍼티만 선택해 새로운 오브젝트 타입을 만드는 내장 제네릭 Pick<T, K>을 이를 사용하지 않고 구현하세요.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 문제: T에서 K 프로퍼티만 선택해 새로운 오브젝트 타입을 만드는 내장 제네릭 Pick<T, K>을 이를 사용하지 않고 구현하세요.
interface Todo {
  title: string
  description: string
  completed: boolean
}
 
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
 
const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
}
cs

 

 

 

👩‍🏫 어떻게 풀어요?

 

풀기전에 간단하게 타입 스크립트에서 Pick 타입은 무엇인지 간단하게 알고 넘어가도록 하겠습니다.

 

Pick 타입은 타입 스크립트에서 일반적인 타입 변환을 쉽게 해주기 위해 제공하는 유틸리티 타입중에 하나입니다. Pick<Type, keys> 형식으로 작성하며, Type에서 프로퍼티 Keys의 집합을 선택해 타입을 생성합니다. 이때, keys 값에는 문자열 리터럴 혹은 유니온 형식의 문자열 리터럴이 올 수 있습니다.

 

아래 예제에서는 유니온 형식의 문자열 리터럴을 keys 값으로 받는 Pick 타입을 사용하여 Todo 인터페이스 타입에서 title과 completed 키만을 갖는 새로운 TodoPreview 타입을 만든것을 확인할 수 있습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}
 
type TodoPreview = Pick<Todo, "title" | "completed">;
 
const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};
 
todo;
cs

 

 

 

 

이번 타입 챌린지 문제에서 원하는 것은 타입 스크립트의 Pick을 사용하지 않고, Pick과 똑같은 기능을 하는 타입을 하나 만들어야 하는 것입니다. 따라서 가져온 타입을 T, 해당 타입의 키를 확장하는 K를 선언해줍시다. 이렇게 선언하면 T 타입의 키값을 K에서 사용할 수 있습니다. 

 

T => Todo
K => Todo 객체의 키값 ("title" | "completed" | "description")
1
2
type MyPick<T, K extends keyof T> = {
};
cs

 

 

 

 

 

그 다음에는 K의 값을 키로 하는 새로운 객체를 만들어야 합니다. 따라서 타입 스크립트의 Mapped Type을 사용합니다.

타입 스크립트의 Mapped Type은 자바 스크립트의 map() 함수를 타입에다가 적용했다고 생각하시면 됩니다. 

 

Mapped Type 사용시, 인덱스 시그니처 형식을 기반으로 작성해야 합니다. 

 

1
2
3
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};
cs

 

Mapped Type을 사용한 구문인 [P in K]: T[P]를 해석해보자면 다음과 같습니다.

[P in K] 에서 P K값을 순차적으로 돌며  K의 값을 갖게 됩니다. 해당 문제에서 K는 "title" | "completed" 이므로  처음에 설정된 P값은 "title"이 됩니다. 따라서  처음 루프에서 [P in K]: T[P]는 "title" : T["title"]이 됩니다. 다음 값인 completed도 같은 과정을 거치게 되고, 결국 타입이 string이며 "title"과 "completed"를 키로 하는 TodoPreview 타입이 만들어지게 됩니다.

 

 

 

 

👾 트리스티의 정답 

 

1
2
3
4
5
// 정답
// 다른 정답도 있을 수 있습니다!
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};
cs