๐ŸŽญ ์ธ๋ฑ์Šค ํƒ€์ž…(Index Types)์œผ๋กœ ๊ฐ์ฒด ์†์„ฑ ์ ‘๊ทผํ•˜๊ธฐ: TypeScript์˜ ๋งˆ๋ฒ• ๐Ÿง™โ€โ™‚๏ธ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐ŸŽญ ์ธ๋ฑ์Šค ํƒ€์ž…(Index Types)์œผ๋กœ ๊ฐ์ฒด ์†์„ฑ ์ ‘๊ทผํ•˜๊ธฐ: TypeScript์˜ ๋งˆ๋ฒ• ๐Ÿง™โ€โ™‚๏ธ

 

 

์•ˆ๋…•ํ•˜์„ธ์š”, ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ TypeScript์˜ ๊ฟ€์žผ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ธ '์ธ๋ฑ์Šค ํƒ€์ž…(Index Types)'์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ์ด๊ฑฐ ์ง„์งœ ๋Œ€๋ฐ•์ธ ๊ฑฐ ์•„์‹œ์ฃ ? ใ…‹ใ…‹ใ…‹ ๊ฐ์ฒด ์†์„ฑ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์™„์ „ ๋ ˆ๋ฒจ์—… ์‹œ์ผœ์ฃผ๋Š” ๋…€์„์ด๋ผ๊ณ ์š”! ๐Ÿ˜Ž

์—ฌ๋Ÿฌ๋ถ„, ํ˜น์‹œ ์žฌ๋Šฅ๋„ท์ด๋ผ๋Š” ์‚ฌ์ดํŠธ ์•„์„ธ์š”? ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ฑฐ๋ž˜ํ•˜๋Š” ํ”Œ๋žซํผ์ธ๋ฐ, ์ด๋Ÿฐ ์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ TypeScript๋ฅผ ์“ฐ๋ฉด ์–ผ๋งˆ๋‚˜ ํŽธํ• ์ง€ ์ƒ์ƒ์ด ๊ฐ€์‹œ๋‚˜์š”? ํŠนํžˆ ์ธ๋ฑ์Šค ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ •๋ณด๋‚˜ ์žฌ๋Šฅ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์™„์ „ ๊ฟ€์ด์—์š”! ์ž, ๊ทธ๋Ÿผ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์‹œ์ž‘ํ•ด๋ณผ๊นŒ์š”? ๐Ÿš€

๐Ÿ”‘ ํ•ต์‹ฌ ํฌ์ธํŠธ: ์ธ๋ฑ์Šค ํƒ€์ž…์€ TypeScript์—์„œ ๊ฐ์ฒด์˜ ์†์„ฑ์— ๋™์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด์—์š”. ์ด๋ฅผ ํ†ตํ•ด ํƒ€์ž… ์•ˆ์ •์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์œ ์—ฐํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

๐ŸŽจ ์ธ๋ฑ์Šค ํƒ€์ž…, ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋‚˜์š”?

์ธ๋ฑ์Šค ํƒ€์ž…, ์ฒ˜์Œ ๋“ค์œผ๋ฉด ์ข€ ์–ด๋ ค์›Œ ๋ณด์ด์ฃ ? ๊ทผ๋ฐ ๊ฑฑ์ • ๋งˆ์„ธ์š”! ์ƒ๊ฐ๋ณด๋‹ค ์‰ฌ์›Œ์š”. ๊ทธ๋ƒฅ ๊ฐ์ฒด์˜ ํ‚ค๋ฅผ ๋ฌธ์ž์—ด์ด๋‚˜ ์ˆซ์ž๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฑฐ์˜ˆ์š”. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”?


interface UserInfo {
  name: string;
  age: number;
  [key: string]: string | number;
}

const user: UserInfo = {
  name: "๊น€์ฒ ์ˆ˜",
  age: 25,
  hobby: "์ฝ”๋”ฉ",
  favoriteNumber: 42
};

์—ฌ๊ธฐ์„œ [key: string]: string | number; ์ด ๋ถ€๋ถ„์ด ๋ฐ”๋กœ ์ธ๋ฑ์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜์˜ˆ์š”. ์ด๊ฒŒ ๋ญ๋ƒ๊ณ ์š”? ์‰ฝ๊ฒŒ ๋งํ•ด์„œ "์–ด๋–ค ๋ฌธ์ž์—ด ํ‚ค๋“  ๋‹ค ๋ฐ›์•„๋“ค์ผ ์ˆ˜ ์žˆ๊ณ , ๊ทธ ๊ฐ’์€ ๋ฌธ์ž์—ด์ด๋‚˜ ์ˆซ์ž์ผ ์ˆ˜ ์žˆ์–ด!"๋ผ๊ณ  TypeScriptํ•œํ…Œ ๋งํ•ด์ฃผ๋Š” ๊ฑฐ์˜ˆ์š”. ์™„์ „ ์ž์œ ๋กœ์›Œ! ใ…‹ใ…‹ใ…‹

๐Ÿ’ก ๊ฟ€ํŒ: ์ธ๋ฑ์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์— ์›ํ•˜๋Š” ๋งŒํผ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ž์‹ ์˜ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ํ”„๋กœํ•„์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”!

๐ŸŽญ ์ธ๋ฑ์Šค ํƒ€์ž…์˜ ๋งˆ๋ฒ•: ํ‚ค์˜ค๋ธŒ(keyof) ์—ฐ์‚ฐ์ž

์ž, ์ด์ œ ์ง„์งœ ์žฌ๋ฏธ์žˆ๋Š” ๋ถ€๋ถ„์ด ๋‚˜์™€์š”! 'keyof' ์—ฐ์‚ฐ์ž๋ฅผ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋…€์„์€ ์ •๋ง ๋Œ€๋‹จํ•ด์š”. ๊ฐ์ฒด ํƒ€์ž…์˜ ๋ชจ๋“  ํ‚ค๋ฅผ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๊ฑฐ๋“ ์š”. ๋ญ” ์†Œ๋ฆฌ๋ƒ๊ณ ์š”? ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด ๋ฐ”๋กœ ์ดํ•ด๋  ๊ฑฐ์˜ˆ์š”!


interface Talent {
  singing: number;
  dancing: number;
  acting: number;
}

type TalentKey = keyof Talent; // "singing" | "dancing" | "acting"

function improveTalent(person: Talent, skill: TalentKey): void {
  person[skill]++;
}

let idol: Talent = {
  singing: 8,
  dancing: 9,
  acting: 7
};

improveTalent(idol, "dancing"); // OK
improveTalent(idol, "cooking"); // ์—๋Ÿฌ! "cooking"์€ Talent์˜ ํ‚ค๊ฐ€ ์•„๋‹ˆ์—์š”.

์—ฌ๊ธฐ์„œ keyof Talent๋Š” "singing", "dancing", "acting" ์ค‘ ํ•˜๋‚˜๋งŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ž์‹ ์˜ ์žฌ๋Šฅ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์„œ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”! ๐Ÿ˜‰

์ธ๋ฑ์Šค ํƒ€์ž…๊ณผ keyof ์—ฐ์‚ฐ์ž ์„ค๋ช… ์ธ๋ฑ์Šค ํƒ€์ž…์˜ ๋งˆ๋ฒ•: keyof ์—ฐ์‚ฐ์ž Talent ์ธํ„ฐํŽ˜์ด์Šค singing: number dancing: number acting: number TalentKey ํƒ€์ž… "singing" | "dancing" | "acting"

๐Ÿ” ์ธ๋ฑ์Šค ์ ‘๊ทผ ํƒ€์ž…: ๊ฐ์ฒด์˜ ์†์„ฑ ํƒ€์ž… ๊ฐ€์ ธ์˜ค๊ธฐ

์ด๋ฒˆ์—” ๋” ์‹ ๊ธฐํ•œ ๊ฑธ ๋ณด์—ฌ๋“œ๋ฆด๊ฒŒ์š”! ์ธ๋ฑ์Šค ์ ‘๊ทผ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์˜ ํŠน์ • ์†์„ฑ์˜ ํƒ€์ž…์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ด๋ƒ๊ณ ์š”? ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด ๋ฐ”๋กœ ์ดํ•ด๋  ๊ฑฐ์˜ˆ์š”!


interface User {
  id: number;
  name: string;
  email: string;
}

type UserEmail = User["email"]; // string ํƒ€์ž…

function sendEmail(email: UserEmail) {
  console.log(`์ด๋ฉ”์ผ ์ „์†ก: ${email}`);
}

sendEmail("user@example.com"); // OK
sendEmail(123); // ์—๋Ÿฌ! number๋Š” string ํƒ€์ž…์ด ์•„๋‹ˆ์—์š”.

์—ฌ๊ธฐ์„œ User["email"]์€ User ์ธํ„ฐํŽ˜์ด์Šค์˜ email ์†์„ฑ์˜ ํƒ€์ž…์„ ๊ฐ€์ ธ์™€์š”. ์ฆ‰, string ํƒ€์ž…์ด ๋˜๋Š” ๊ฑฐ์ฃ . ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํƒ€์ž…์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ •๋ง ํŽธ๋ฆฌํ•ด์š”! ๐Ÿ˜Š

๐Ÿš€ ์‘์šฉ ํŒ: ์ด๋Ÿฐ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉด ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ์‚ฌ์ดํŠธ์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ํƒ€์ž… ์•ˆ์ •์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ด๋ฉ”์ผ ์ „์†ก ํ•จ์ˆ˜์—๋Š” ๋ฐ˜๋“œ์‹œ ์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ํƒ€์ž…๋งŒ ์ „๋‹ฌ๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์ฃ !

๐ŸŽก ๋งคํ•‘๋œ ํƒ€์ž…: ๊ธฐ์กด ํƒ€์ž…์„ ๋ณ€ํ˜•์‹œํ‚ค๊ธฐ

์ด์ œ ์ •๋ง ๊ณ ๊ธ‰ ๊ธฐ์ˆ ๋กœ ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค! ๋งคํ•‘๋œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์กด ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฒŒ ๋ฐ”๋กœ TypeScript์˜ ์ง„์ •ํ•œ ํž˜์ด์ฃ ! ใ…‹ใ…‹ใ…‹


type Readonly<t> = {
  readonly [P in keyof T]: T[P];
};

interface Skill {
  name: string;
  level: number;
}

type ReadonlySkill = Readonly<skill>;

let mySkill: ReadonlySkill = {
  name: "ํ”„๋กœ๊ทธ๋ž˜๋ฐ",
  level: 8
};

mySkill.level = 9; // ์—๋Ÿฌ! ์ฝ๊ธฐ ์ „์šฉ ์†์„ฑ์ด์—์š”.
</skill></t>

์—ฌ๊ธฐ์„œ Readonly๋Š” T ํƒ€์ž…์˜ ๋ชจ๋“  ์†์„ฑ์„ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์‹ค์ˆ˜๋กœ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์ฃ . ์•ˆ์ „ํ•œ ์ฝ”๋”ฉ life! ๐Ÿ‘

๋งคํ•‘๋œ ํƒ€์ž… ์„ค๋ช… ๋งคํ•‘๋œ ํƒ€์ž…์˜ ๋งˆ๋ฒ• Skill ์ธํ„ฐํŽ˜์ด์Šค name: string level: number ReadonlySkill ํƒ€์ž… readonly name: string readonly level: number

๐ŸŽญ ์กฐ๊ฑด๋ถ€ ํƒ€์ž…: ํƒ€์ž…์˜ if-else ๋ฌธ

์ž, ์ด์ œ ์ง„์งœ ๊ณ ๊ธ‰ ์Šคํ‚ฌ์ด ๋‚˜์˜ต๋‹ˆ๋‹ค! ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฑด ๋งˆ์น˜ ํƒ€์ž… ์‹œ์Šคํ…œ์—์„œ์˜ if-else ๋ฌธ๊ณผ ๊ฐ™์•„์š”!


type IsString<t> = T extends string ? true : false;

type Check1 = IsString<"hello">; // true
type Check2 = IsString<42>; // false

type ExtractArray<t> = T extends Array<infer u> ? U : never;

type NumberArray = ExtractArray<number>; // number
type StringArray = ExtractArray<string>; // string
type MixedArray = ExtractArray<(number | string)[]>; // number | string
</string></number></infer></t></t>

์—ฌ๊ธฐ์„œ T extends string ? true : false๋Š” "T๊ฐ€ string ํƒ€์ž…์„ ํ™•์žฅํ•˜๋ฉด true, ์•„๋‹ˆ๋ฉด false"๋ผ๋Š” ์˜๋ฏธ์˜ˆ์š”. ๊ทธ๋ฆฌ๊ณ  T extends Array ? U : never๋Š” "T๊ฐ€ ๋ฐฐ์—ด์ด๋ฉด ๊ทธ ์š”์†Œ์˜ ํƒ€์ž…์„ ์ถ”์ถœํ•˜๊ณ , ์•„๋‹ˆ๋ฉด never"๋ผ๋Š” ๋œป์ด์—์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํƒ€์ž…์„ ๋™์ ์œผ๋กœ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”! ๐Ÿ˜Ž

๐Ÿ”ฅ ๊ณ ๊ธ‰ ํŒ: ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋ฉด ์žฌ๋Šฅ๋„ท์—์„œ ์‚ฌ์šฉ์ž์˜ ์žฌ๋Šฅ ์œ ํ˜•์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, ์Œ์•… ๊ด€๋ จ ์žฌ๋Šฅ๊ณผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ด€๋ จ ์žฌ๋Šฅ์„ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ฃ !

๐ŸŒˆ ์ธ๋ฑ์Šค ํƒ€์ž…์˜ ์‹ค์ „ ์‘์šฉ: ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

์ž, ์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šด ๊ฑธ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณผ๊นŒ์š”? ์˜ˆ๋ฅผ ๋“ค์–ด, ํผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•  ๋•Œ ์ธ๋ฑ์Šค ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ์ •๋ง ํŽธ๋ฆฌํ•ด์š”!


interface ValidationRules {
  required?: boolean;
  minLength?: number;
  maxLength?: number;
  pattern?: RegExp;
}

interface FormFields {
  username: ValidationRules;
  email: ValidationRules;
  password: ValidationRules;
}

const formValidationRules: FormFields = {
  username: { required: true, minLength: 3, maxLength: 20 },
  email: { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ },
  password: { required: true, minLength: 8 }
};

function validate<t extends keyof formfields>(
  field: T,
  value: string,
  rules: FormFields[T]
): boolean {
  if (rules.required && !value) {
    console.log(`${field} is required`);
    return false;
  }
  if (rules.minLength && value.length < rules.minLength) {
    console.log(`${field} should be at least ${rules.minLength} characters`);
    return false;
  }
  if (rules.maxLength && value.length > rules.maxLength) {
    console.log(`${field} should be no more than ${rules.maxLength} characters`);
    return false;
  }
  if (rules.pattern && !rules.pattern.test(value)) {
    console.log(`${field} does not match the required pattern`);
    return false;
  }
  return true;
}

// ์‚ฌ์šฉ ์˜ˆ
validate("username", "john", formValidationRules.username); // true
validate("email", "invalid-email", formValidationRules.email); // false
validate("password", "123", formValidationRules.password); // false
</t>

์ด ์˜ˆ์ œ์—์„œ T extends keyof FormFields๋ฅผ ์‚ฌ์šฉํ•ด์„œ field ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ FormFields์˜ ํ‚ค ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค๊ณ  ์ง€์ •ํ–ˆ์–ด์š”. ๊ทธ๋ฆฌ๊ณ  FormFields[T]๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•ด๋‹น ํ•„๋“œ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ทœ์น™์„ ๊ฐ€์ ธ์™”์ฃ . ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํƒ€์ž… ์•ˆ์ •์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์œ ์—ฐํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”! ๐Ÿ‘

๐Ÿ’ก ์‹ค์šฉ์ ์ธ ํŒ: ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ์žฌ๋Šฅ๋„ท์—์„œ ์‚ฌ์šฉ์ž ๋“ฑ๋ก ํผ์ด๋‚˜ ์žฌ๋Šฅ ๋“ฑ๋ก ํผ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ์–ด์š”. ๊ฐ ํ•„๋“œ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ทœ์น™์„ ์ ์šฉํ•˜๋ฉด์„œ๋„, ํƒ€์ž… ์•ˆ์ •์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์ฃ !

๐Ÿ† ์ธ๋ฑ์Šค ํƒ€์ž…์˜ ๊ณ ๊ธ‰ ๊ธฐ์ˆ : ์žฌ๊ท€์  ํƒ€์ž…

์ด์ œ ์ •๋ง ๊ณ ๊ธ‰ ์Šคํ‚ฌ๋กœ ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค! ์žฌ๊ท€์  ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ์ค‘์ฒฉ ๊ตฌ์กฐ๋„ ํƒ€์ž… ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฑด ์ •๋ง ๋Œ€๋ฐ•์ด์—์š”! ใ…‹ใ…‹ใ…‹


type NestedObject<t> = {
  [K in keyof T]: T[K] extends object ? NestedObject<t> : T[K];
};

interface DeepUser {
  name: string;
  age: number;
  address: {
    street: string;
    city: string;
    country: {
      name: string;
      code: string;
    };
  };
  hobbies: string[];
}

type DeepReadonly<t> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<t> : T[K];
};

const user: DeepReadonly<deepuser> = {
  name: "๊น€์ฒ ์ˆ˜",
  age: 30,
  address: {
    street: "๊ฐ•๋‚จ๋Œ€๋กœ",
    city: "์„œ์šธ",
    country: {
      name: "๋Œ€ํ•œ๋ฏผ๊ตญ",
      code: "KR"
    }
  },
  hobbies: ["์ฝ”๋”ฉ", "๋…์„œ"]
};

// ๋‹ค์Œ ์ฝ”๋“œ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค!
// user.name = "์ด์˜ํฌ"; // ์—๋Ÿฌ: ์ฝ๊ธฐ ์ „์šฉ ์†์„ฑ์ด๋ฏ€๋กœ 'name'์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
// user.address.city = "๋ถ€์‚ฐ"; // ์—๋Ÿฌ: ์ฝ๊ธฐ ์ „์šฉ ์†์„ฑ์ด๋ฏ€๋กœ 'city'์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
// user.address.country.code = "US"; // ์—๋Ÿฌ: ์ฝ๊ธฐ ์ „์šฉ ์†์„ฑ์ด๋ฏ€๋กœ 'code'์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
// user.hobbies.push("์—ฌํ–‰"); // ์—๋Ÿฌ: 'readonly string[]' ํ˜•์‹์— 'push' ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.
</deepuser></t></t></t></t>

์—ฌ๊ธฐ์„œ DeepReadonly ํƒ€์ž…์€ ๊ฐ์ฒด์˜ ๋ชจ๋“  ์†์„ฑ์„ ์žฌ๊ท€์ ์œผ๋กœ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊นŠ์ด ์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์ฃ ! ๐Ÿ˜Ž

์žฌ๊ท€์  ํƒ€์ž… ์„ค๋ช… ์žฌ๊ท€์  ํƒ€์ž…์˜ ๋งˆ๋ฒ• DeepUser name: string age: number address: object hobbies: string[] DeepReadonly readonly name: string readonly age: number readonly address: object readonly hobbies: readonly string[]

๐ŸŽจ ์ธ๋ฑ์Šค ํƒ€์ž…๊ณผ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์˜ ์กฐํ•ฉ

์ด์ œ ์ธ๋ฑ์Šค ํƒ€์ž…๊ณผ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์„ ์กฐํ•ฉํ•ด์„œ ๋” ๊ฐ•๋ ฅํ•œ ํƒ€์ž…์„ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”? ์ด๊ฑด ์ •๋ง ๋Œ€๋ฐ• ๊ธฐ๋Šฅ์ด์—์š”! ใ…‹ใ…‹ใ…‹


type Skill = "programming" | "design" | "marketing";

type SkillLevel = "beginner" | "intermediate" | "expert";

type UserSkills = {
  [K in Skill]?: SkillLevel;
};

const user: UserSkills = {
  programming: "expert",
  design: "intermediate"
};

function improveSkill(user: UserSkills, skill: Skill): UserSkills {
  const currentLevel = user[skill];
  let newLevel: SkillLevel;

  switch (currentLevel) {
    case "beginner":
      newLevel = "intermediate";
      break;
    case "intermediate":
      newLevel = "expert";
      break;
    case "expert":
      newLevel = "expert";
      break;
    default:
      newLevel = "beginner";
  }

  return { ...user, [skill]: newLevel };
}

const updatedUser = improveSkill(user, "design");
console.log(updatedUser); // { programming: "expert", design: "expert" }

์—ฌ๊ธฐ์„œ [K in Skill]?: SkillLevel;๋Š” Skill ์œ ๋‹ˆ์˜จ์˜ ๊ฐ ๊ฐ’์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๊ณ , ๊ทธ ๊ฐ’์œผ๋กœ SkillLevel์„ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด ํƒ€์ž…์„ ๋งŒ๋“ค์–ด์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์‚ฌ์šฉ์ž์˜ ์Šคํ‚ฌ์„ ํƒ€์ž… ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์ฃ ! ๐Ÿ‘

๐ŸŒŸ ์ฐฝ์˜์ ์ธ ํŒ: ์ด๋Ÿฐ ๋ฐฉ์‹์„ ํ™œ์šฉํ•˜๋ฉด ์žฌ๋Šฅ๋„ท์—์„œ ์‚ฌ์šฉ์ž์˜ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ๊ณผ ๊ทธ ์ˆ˜์ค€์„ ํšจ๊ณผ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”. ๊ฐ ์žฌ๋Šฅ๋งˆ๋‹ค ๋ ˆ๋ฒจ์„ ์„ค์ •ํ•˜๊ณ , ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ฃ !

๐ŸŽญ ์ธ๋ฑ์Šค ํƒ€์ž…๊ณผ ์ œ๋„ค๋ฆญ์˜ ํ™˜์ƒ์ ์ธ ์ฝœ๋ผ๋ณด

์ž, ์ด์ œ ์ •๋ง ๊ณ ๊ธ‰ ์Šคํ‚ฌ์˜ ๋ํŒ์™•์ด ๋‚˜์˜ต๋‹ˆ๋‹ค! ์ธ๋ฑ์Šค ํƒ€์ž…๊ณผ ์ œ๋„ค๋ฆญ์„ ์กฐํ•ฉํ•˜๋ฉด ์ •๋ง ๋†€๋ผ์šด ์ผ์„ ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฑด ์ง„์งœ TypeScript์˜ ํŒŒ์›Œ๋ฅผ ์ œ๋Œ€๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๊ฑฐ์˜ˆ์š”! ใ…‹ใ…‹ใ…‹