TS_Pick<T, K>

jhson·2024년 1월 19일
0

typescript

목록 보기
4/7

문제: Role과 Permissions 타입이 주어졌을 때,
각 Role에 대한 Permissions을 매핑하는 새로운 타입을 만드세요.

type Role = "admin" | "user" | "guest";
type Permissions = "read" | "write" | "delete";

// 여기에 새로운 타입을 만드세요.

첫 번째 시도

type Role = "admin" | "user" | "guest";
type Permissions = "read" | "write" | "delete";

type RolePermission = [Role in keyof Permissions]: Role[Permissions];

- 나의 의도 :

  • 이렇게 하면 될 것 같은데...? 했으나 역시 안된다.
    말이 안되니까 안되는 거다ㅎㅎ
  • 여기서 keyof Permissions는 "read" | "write" | "delete"가 되며, 따라서 Role in keyof Permissions는 각각 "admin" | "user" | "guest" in "read" | "write" | "delete"가 되는 것이다.

첫 번째 고민

type Role = "admin"| "user"| "guest";
type Permissions = "read"|"write"|"delete";

type RolePermissions = [keyof Permissions]: Role[Permissions];
  • 그렇다면 Permissions의 키와 동일한 키를 가지도록 하고 이걸 Role의 각 요소들 이 해당 키 값을 가져갈 수 있는 구조로 만들면 어떨까?
  • 이렇게 할 경우 문법적 오류가 있음
  • 배열의 형태로 타입을 정의하는 경우, 배열의 인덱스로 접근하는 방식은 사용할 수 없다. 대신, TypeScript에서는 매핑을 사용하여 특정 키와 그에 해당하는 값의 타입을 정의

두 번째 고민

type Role = "admin"| "user"| "guest";
type Permissions = "read"|"write"|"delete";

type RolePermissions = {[P in Role]: Permissions[]};

const rolePermissions: RolePermissions = {
    admin: ["read", "write", "delete"],
    user: ["read", "write"],
    guest: ["read"],
}
//{
  admin: [ 'read', 'write', 'delete' ],
  user: [ 'read', 'write' ],
  guest: [ 'read' ]
}
  • [P in Role] :
    - Role 타입의 각 요소에 대해 반복(iteration)을 나타낸다.
    - 여기에서 P는 반복되는 각 요소를 나타내며, Role은 유니온 타입인 "admin" | "user" | "guest"를 의미
    - 따라서 [P in Role]는 "admin", "user", "guest"에 대해 각각 반복하면서 해당 값을 P에 할당하라는 의미이다.
  • 주로 객체의 키를 동적으로 정의할 때 사용된다.
    - 예를 들어, { [P in Role]: string }은 Role 타입의 각 요소에 대해 문자열 값을 가지는 객체를 정의한다.

세 번째 고민

  • 그렇다면 Role, Permissions 타입이 튜플이면 어떨까?
type Role = ["admin", "user", "guest"];
type Permissions = ["read", "write","delete"];

type RolePermissions = [keyof Permissions]: Role[Permissions];

- 나의 의도:

Permission의 키를 가지는 타입이고 이것의 타입은 Role의 각 키 값에 Permission의 키 값들을 매핑한다...? 라는 것을 의도하고 싶었다.

  • 그러나 해당 코드는 오류가 있었음
  • TypeScript에서는 인덱스 시그니처(Index Signature)를 사용하여 동적으로 속성을 생성하는 것이 가능하지만, 배열 문법을 사용하는 방식은 아니다.배열의 인덱스에는 숫자만 사용할 수 있다.

수정한 코드

type Role = ["admin" | "user" | "guest"];
type Permissions = ["read" | "write" | "delete"];

type RolePermissions = {
  [P in Role[number]]: Permissions[number];
};

const rolePermissions: RolePermissions = {
  admin: "delete",
  user: "write",
  guest: "read",
};

console.log(rolePermissions)
// { admin: 'delete', user: 'write', guest: 'read' }
  • [P in Role[number]]는 Role 튜플의 각 요소에 대해 반복하고, 해당 요소에 대응하는 Permissions 튜플의 타입을 할당한다.
  • Permissions[number]는 Permissions 튜플의 각 요소의 유니온 타입을 나타낸다.
  • 그러나 튜플을 사용하는 것이 필요한 상황이 아니라면, 보통은 객체 형태로 정의하는 것이 더 자연스러움

Record<K, T>

  • 특정 타입의 속성을 다른 타입으로 매핑할 때 사용
  • 주로 객체의 속성들을 초기화하거나 매핑할 때 유용하게 사용
  • K: 새로운 객체의 속성들을 정의하는 키들의 유니온 타입
    T: 키에 대응하는 값의 타입을 정의

Record 유틸리티 타입을 이용한 풀이

type Role = "admin" | "user" | "guest";
type Permissions = "read" | "write" | "delete";

// 여기에 새로운 타입을 만드세요.
type RolePermissionsMap = Record<Role, Permissions[]>;

const rolePermissions: RolePermissionsMap = {
  admin: ["read", "write", "delete"],
  user: ["read", "write"],
  guest: ["read"],
};
profile
게임회사 주니어 개발pm에서 프론트엔드 개발자로 전향하는 과정

0개의 댓글