๐Ÿ“šย ๋งต๋“œ(Mapped Types)?

๋งต๋“œ ํƒ€์ž…์€ ๊ธฐ์กด ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ map() ํ•จ์ˆ˜๋ฅผ ํƒ€์ž…์— ์ ์šฉํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๊ฐ€์ง„๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ for in ๋ฌธ๋ฒ•๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋ฉฐ, Kํƒ€์ž…์˜ ๊ฐ’์„ ๊ฐ๊ฐ ์ˆœํšŒํ•˜์—ฌ Tํƒ€์ž…์„ ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด์˜ ํ‚ค๋กœ ์ •์˜๊ฐ€ ๋œ๋‹ค.

{ [ P in K ] : T }
{ [ P in K ]? : T } 
{ readonly [ P in K ] : T }
{ readonly [ P in K ]? : T }
  1. ๋ชจ๋“ ย ์†์„ฑ์„ ์„ ํƒ์ (Optional)/ํ•„์ˆ˜(required)๋กœ ๋งŒ๋“ค๊ธฐ
type Person = {
  name: string;
  age: number;
};

// ์œ ํ‹ธ๋ฆฌํ‹ฐํƒ€์ž… Partial<Person>๊ณผ ๋™์ผ
type PartialPerson = {
  [K in keyof Person]?: Person[K];
};

type User = {
    name?: string;
    age?: number;
};

// ์œ ํ‹ธ๋ฆฌํ‹ฐํƒ€์ž… Required<User>์™€ ๋™์ผ
type RequiredUser = {
    [K in keyof User]-?: User[K];
};
  1. ์œ ํ‹ธ๋ฆฌํ‹ฐํƒ€์ž… ๋งŒ๋“ค๊ธฐ(์˜ˆ์‹œ: Pick)
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

type NameOnly = Pick<Person, 'name'>;
  1. ๋ชจ๋“  ์†์„ฑ์„ ReadOnly๋กœ ๋งŒ๋“ค๊ธฐ
type ReadonlyPerson = {
  readonly [K in keyof Person]: Person[K];
};

// ๊ฒฐ๊ณผ:
// {
//   readonly name: string;
//   readonly age: number;
// }
  1. ๋ชจ๋“  ์†์„ฑ ํƒ€์ž…์„ ํŠน์ • ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ(์˜ˆ์‹œ: string)
type Stringify<T> = {
  [K in keyof T]: string;
};

type StringifiedPerson = Stringify<Person>;

// ๊ฒฐ๊ณผ:
// {
//   name: string;
//   age: string;
// }
  1. ํƒ€์ž…์„ ์ขํ˜€ ์กฐ๊ฑด๋ถ€๋กœ ์†์„ฑ ์ œ์™ธํ•˜๊ธฐ
// ๋งŒ์•ฝ ์†์„ฑ์˜ ํƒ€์ž…์ดย nullย ๋˜๋Š”ย undefined๋ฅผ ํฌํ•จํ•˜๋ฉดย never๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ํƒ€์ž… ์ œ๊ฑฐ ํšจ๊ณผ
type NonNullable<T> = {
  [K in keyof T]: T[K] extends null | undefined ? never : T[K];
};

type User = {
  name: string | null;
  age: number | undefined;
  email: string;
};

type NonNullableUser = NonNullable<User>;
// ๊ฒฐ๊ณผ:
// {
//   name: string;  // null์ด ์ œ๊ฑฐ๋จ
//   age: number;   // undefined๊ฐ€ ์ œ๊ฑฐ๋จ
//   email: string; // ๋ณ€๊ฒฝ ์—†์Œ
// }

๐Ÿ”ย ๋งต๋“œ ์ฃผ์˜์‚ฌํ•ญ