TypeScript generic๊ณผ keyof๋กœ ํƒ€์ž… ์•ˆ์ „์„ฑ ๋†’์ด๊ธฐ

TypeScript generic๊ณผ keyof๋กœ ํƒ€์ž… ์•ˆ์ „์„ฑ ๋†’์ด๊ธฐ

D
dongAuthor
7 min read

TypeScript๋กœ ์ž‘์—…ํ•˜๋‹ค ๋ณด๋ฉด ๋‹ค์–‘ํ•œ ํƒ€์ž…์— ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์ฃ . ๋ฐ”๋กœ ์ด๋Ÿด ๋•Œ ์ œ๋„ค๋ฆญ(Generics)์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  keyof ์—ฐ์‚ฐ์ž์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์˜ ์†์„ฑ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์–ด์š”. ์ด ๊ธ€์—์„œ๋Š” TypeScript์˜ ์ œ๋„ค๋ฆญ๊ณผ keyof๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์‚ดํŽด๋ณผ๊ฒŒ์š”. ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค๋ฌด์—์„œ ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŒจํ„ด๊นŒ์ง€, ๋‹จ๊ณ„๋ณ„๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.


TypeScript ์ œ๋„ค๋ฆญ์˜ ๊ธฐ์ดˆ

์ œ๋„ค๋ฆญ์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ํ•ต์‹ฌ ๋„๊ตฌ์ด๋ฉฐ ๋‹ค์–‘ํ•œ ํƒ€์ž…์— ๋Œ€์‘ํ•˜๋ฉด์„œ ํƒ€์ž… ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ํƒ€์ž…์ด ์•„๋‹Œ ๋‹ค์–‘ํ•œ ํƒ€์ž…์— ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์ฃ . ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์˜ˆ์ œ์ธ identity ํ•จ์ˆ˜๋ฅผ ๋ณผ๊นŒ์š”?

function identity<T>(arg: T): T {
  return arg;
}

์—ฌ๊ธฐ์„œ <T>๋Š” ํƒ€์ž… ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ „๋‹ฌ๋˜๋Š” ํƒ€์ž…์„ ์บก์ฒ˜ํ•ด์„œ, ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ์˜ ํƒ€์ž…์„ ์ผ์น˜์‹œ์ผœ์š”. ํƒ€์ž… ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์€ ์ž์œ ๋กญ๊ฒŒ ์ •ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ด€๋ก€์ ์œผ๋กœ T(Type์˜ ์•ฝ์ž)๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ œ๋„ค๋ฆญ ํ•จ์ˆ˜ ํ˜ธ์ถœํ•˜๊ธฐ

์ œ๋„ค๋ฆญ์€ ๋ช…์‹œ์  ํƒ€์ž… ์ธ์ž ๋˜๋Š” ํƒ€์ž… ์ถ”๋ก ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ€๋Šฅํ•˜๋ฉด ํƒ€์ž… ์ถ”๋ก ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์ œ๋„ค๋ฆญ ํ•จ์ˆ˜๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์–ด์š”.

๋ช…์‹œ์  ํƒ€์ž… ์ธ์ž ์ „๋‹ฌ:

let output = identity<string>("myString");

ํƒ€์ž… ์ถ”๋ก  ํ™œ์šฉ:

let output = identity("myString");

๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์ด ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์„œ, TypeScript๊ฐ€ ์ž๋™์œผ๋กœ ํƒ€์ž…์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด ๋ฐฉ์‹์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

ํƒ€์ž… ๋ณ€์ˆ˜๊ฐ€ ์ฃผ๋Š” ์œ ์—ฐ์„ฑ

์ œ๋„ค๋ฆญ์€ ๋‹ค์–‘ํ•œ ํƒ€์ž…์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜์šฉํ•˜๊ณ , ๋ถˆ์ผ์น˜ํ•œ ํƒ€์ž… ์กฐํ•ฉ์€ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

function toArray<T>(a: T, b: T) {
  return [a, b];
}

toArray<string>("hello", "world"); // string[] ํƒ€์ž…
toArray<number>(1, 2); // number[] ํƒ€์ž…

๋งŒ์•ฝ ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ์ธ์ž๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์ปดํŒŒ์ผ ์‹œ์ ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค:

toArray<string>("hello", 1); // ํƒ€์ž… ์—๋Ÿฌ!

keyof ์—ฐ์‚ฐ์ž๋กœ ์ œ๋„ค๋ฆญ ์ œ์•ฝํ•˜๊ธฐ

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

keyof์˜ ๊ธฐ๋ณธ ๋™์ž‘

interface Person {
  name: string;
  age: number;
}

type PersonKeys = keyof Person; // "name" | "age"

์ œ๋„ค๋ฆญ ์ œ์•ฝ์œผ๋กœ ํƒ€์ž… ์•ˆ์ „์„ฑ ํ™•๋ณดํ•˜๊ธฐ

Key extends keyof Type ์ œ์•ฝ์„ ํ†ตํ•ด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์†์„ฑ ์ ‘๊ทผ์„ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key];
}

const person = {
  name: "Anna",
  age: 30
};

getProperty(person, "name"); // โœ… ์ •์ƒ ๋™์ž‘
getProperty(person, "email"); // โŒ ํƒ€์ž… ์—๋Ÿฌ!
๐Ÿฉผ

ํ•ต์‹ฌ ํŒ
์ œ๋„ค๋ฆญ ์ œ์•ฝ์€ โ€œ์‚ฌ์šฉ์„ ํ—ˆ์šฉํ•  ํ‚ค์˜ ์ง‘ํ•ฉโ€์„ ํƒ€์ž…์œผ๋กœ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ‚ค๋Š” ์• ์ดˆ์— ํ•จ์ˆ˜ ์ธ์ž๋กœ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์†์„ฑ ์„ค์ • ํ•จ์ˆ˜ ๊ตฌํ˜„ํ•˜๊ธฐ

T[K] ์ธ๋ฑ์Šค ์ ‘๊ทผ ํƒ€์ž…์„ ํ™œ์šฉํ•˜๋ฉด ๊ฐ’์˜ ํƒ€์ž…๊นŒ์ง€ ์ •ํ™•ํžˆ ์ œ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
  obj[key] = value;
}

const user = {
  name: "John",
  age: 25
};

setProperty(user, "name", "Jane"); // โœ… ์ •์ƒ
setProperty(user, "name", 30); // โŒ ํƒ€์ž… ์—๋Ÿฌ! (string ํƒ€์ž…์ด์–ด์•ผ ํ•จ)
setProperty(user, "email", "test@test.com"); // โŒ ํƒ€์ž… ์—๋Ÿฌ! (์กด์žฌํ•˜์ง€ ์•Š๋Š” ์†์„ฑ)

์ œ๋„ค๋ฆญ ์ธํ„ฐํŽ˜์ด์Šค์™€ ํด๋ž˜์Šค

ํ•จ์ˆ˜๋ฟ ์•„๋‹ˆ๋ผ ์ธํ„ฐํŽ˜์ด์Šค์™€ ํด๋ž˜์Šค์—๋„ ์ œ๋„ค๋ฆญ์„ ์ ์šฉํ•ด ์œ ์—ฐํ•œ API๋ฅผ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ œ๋„ค๋ฆญ ์ธํ„ฐํŽ˜์ด์Šค

interface GenericIdentityFn<Type> {
  (arg: Type): Type;
}

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

์ œ๋„ค๋ฆญ ํด๋ž˜์Šค

class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
  return x + y;
};

์‹ค๋ฌด ์˜ˆ์ œ:

class User<P> {
  constructor(public payload: P) {
    this.payload = payload;
  }

  getPayload() {
    return this.payload;
  }
}

const user1 = new User<{ name: string; age: number }>({
  name: "Kim",
  age: 28
});

const user2 = new User<string[]>(["admin", "user"]);

์ œ๋„ค๋ฆญ ์ œํ•œ์‚ฌํ•ญ

TypeScript์—์„œ๋Š” ์ œ๋„ค๋ฆญ enum๊ณผ namespace๋Š” ๋งŒ๋“ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” TypeScript์˜ ์„ค๊ณ„์ƒ ์ œํ•œ์‚ฌํ•ญ์ด์—์š”.


๊ธฐ๋ณธ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ

์ œ๋„ค๋ฆญ ๊ธฐ๋ณธ๊ฐ’์„ ์ง€์ •ํ•˜๋ฉด API ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๊ณ  ์ผ๋ฐ˜ ์ผ€์ด์Šค๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function createHTMLElement<T extends HTMLElement = HTMLDivElement>(
  element?: T
): T {
  return element || (document.createElement('div') as T);
}

// ํƒ€์ž… ์ธ์ž๋ฅผ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด HTMLDivElement๊ฐ€ ์‚ฌ์šฉ๋จ
const div = createHTMLElement();

// ๋ช…์‹œ์ ์œผ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์Œ
const button = createHTMLElement<HTMLButtonElement>(
  document.createElement('button')
);

์‹ค์ „ ์˜ˆ์ œ: ํƒ€์ž… ์•ˆ์ „ํ•œ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ํŒจํ„ด

API ์‘๋‹ต์—์„œ ํŠน์ • ์†์„ฑ์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ถ”์ถœํ•˜๋Š” ์œ ํ‹ธ์„ ๋งŒ๋“ค๋ฉด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface ApiResponse {
  data: {
    user: {
      id: number;
      name: string;
      email: string;
    };
    posts: Array<{
      id: number;
      title: string;
    }>;
  };
  meta: {
    timestamp: number;
    version: string;
  };
}

function extractData<T, K extends keyof T>(response: T, key: K): T[K] {
  return response[key];
}

const response: ApiResponse = {
  data: {
    user: { id: 1, name: "Lee", email: "lee@example.com" },
    posts: [{ id: 1, title: "First Post" }]
  },
  meta: {
    timestamp: Date.now(),
    version: "1.0"
  }
};

const data = extractData(response, "data"); // data ํƒ€์ž…์ด ์ž๋™์œผ๋กœ ์ถ”๋ก ๋จ
const meta = extractData(response, "meta"); // meta ํƒ€์ž…๋„ ์ •ํ™•ํžˆ ์ถ”๋ก ๋จ

์ค‘์ฒฉ ์†์„ฑ ์ ‘๊ทผํ•˜๊ธฐ

์ค‘์ฒฉ ํ‚ค๋ฅผ ๋‹จ๊ณ„์ ์œผ๋กœ ์ œ์•ฝํ•˜๋ฉด ๊นŠ์€ ๊ฒฝ๋กœ ์ ‘๊ทผ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function getNestedProperty<
  T,
  K1 extends keyof T,
  K2 extends keyof T[K1]
>(obj: T, key1: K1, key2: K2): T[K1][K2] {
  return obj[key1][key2];
}

const userName = getNestedProperty(response, "data", "user"); // user ๊ฐ์ฒด ํƒ€์ž…

Union ํƒ€์ž…๊ณผ ์ œ๋„ค๋ฆญ ์ œ์•ฝ

extends๋กœ ์œ ๋‹ˆ์˜จ์„ ์ง€์ •ํ•˜๋ฉด ํ—ˆ์šฉ ํƒ€์ž…์„ ์ •ํ™•ํžˆ ํ•œ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function hello<T extends string | number>(msg: T): T {
  return msg;
}

hello(3); // โœ… number ํƒ€์ž…
hello("hi"); // โœ… string ํƒ€์ž…
hello([3, 5]); // โŒ ํƒ€์ž… ์—๋Ÿฌ! (๋ฐฐ์—ด์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Œ)

keyof์™€ typeof๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ

์ƒ์ˆ˜ ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ๊ฐ’ ์œ ๋‹ˆ์˜จ ํƒ€์ž…์„ ์ถ”์ถœํ•˜๋Š” ์‹ค๋ฌด ํŒจํ„ด์€ keyof์™€ typeof์˜ ์กฐํ•ฉ์œผ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

const SUBJECT = {
  Math: 'Math',
  English: 'English',
  Science: 'Science'
} as const;

type Subject = typeof SUBJECT[keyof typeof SUBJECT];
// "Math" | "English" | "Science" ํƒ€์ž…

function getSubjectName(subject: Subject): string {
  return subject;
}

getSubjectName("Math"); // โœ… ์ •์ƒ
getSubjectName("History"); // โŒ ํƒ€์ž… ์—๋Ÿฌ!

์ด ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค: 1) typeof SUBJECT๋กœ ๊ฐ์ฒด ํƒ€์ž…์„ ๊ฐ€์ ธ์˜ด 2) keyof typeof SUBJECT๋กœ ํ‚ค๋“ค(โ€œMathโ€, โ€œEnglishโ€, โ€œScienceโ€)์„ ์ถ”์ถœ 3) typeof SUBJECT[keyof typeof SUBJECT]๋กœ ๊ฐ’๋“ค์˜ ๋ฆฌํ„ฐ๋Ÿด ํƒ€์ž…์„ ์œ ๋‹ˆ์˜จ์œผ๋กœ ๋งŒ๋“ฆ


์ œ๋„ค๋ฆญ๊ณผ keyof์˜ ์‹ค๋ฌด ํ™œ์šฉ ์ด์ 

ํƒ€์ž… ์•ˆ์ „์„ฑ ํ–ฅ์ƒ: ์ปดํŒŒ์ผ ์‹œ์ ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์†์„ฑ ์ ‘๊ทผ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ: ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค๋ฅผ ๋‹ค์–‘ํ•œ ํƒ€์ž…์— ๋Œ€ํ•ด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ์ง€๋ณด์ˆ˜์„ฑ ๊ฐœ์„ : ํƒ€์ž…์ด ๋ช…ํ™•ํ•ด ๋ฆฌํŒฉํ† ๋ง ์‹œ ์•ˆ์ •๋ง ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. IDE ์ง€์› ๊ฐ•ํ™”: ์ž๋™์™„์„ฑ๊ณผ ํƒ€์ž… ํžŒํŠธ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿฉผ

ํ˜„์—… ํŒ
๋™์  ํ‚ค ์ ‘๊ทผ ์œ ํ‹ธ(์˜ˆ: getProperty, setProperty, getNestedProperty)์„ ๋งŒ๋“ค์–ด ๋‘๋ฉด ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์— ์žฌ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์œผ๋กœ ์ด๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ (FAQ)

์ œ๋„ค๋ฆญ ํƒ€์ž… ๋ณ€์ˆ˜๋Š” ๋ช‡ ๊ฐœ๊นŒ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

ํ•„์š”ํ•œ ๋งŒํผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๊ณผ๋„ํ•œ ํƒ€์ž… ๋ณ€์ˆ˜๋Š” ๊ฐ€๋…์„ฑ์„ ํ•ด์น˜๋ฏ€๋กœ ๋ณดํ†ต 2~3๊ฐœ๊ฐ€ ์ ๋‹นํ•ฉ๋‹ˆ๋‹ค.

function transform<T, U, V>(input: T, mapper1: (x: T) => U, mapper2: (x: U) => V): V {
  return mapper2(mapper1(input));
}

keyof๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹์„๊นŒ์š”?

๋™์  ์†์„ฑ ์ ‘๊ทผ, ๋งคํ•‘/๋ณ€ํ™˜ ์œ ํ‹ธ, ํƒ€์ž… ์•ˆ์ „ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ, ์ƒํƒœ ๊ด€๋ฆฌ ๋“ฑ์—์„œ ์†์„ฑ ์œ ํšจ์„ฑ์„ ๋ณด์žฅํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด์˜ ์†์„ฑ์— ์•ˆ์ „ํ•˜๊ฒŒ ์ ‘๊ทผํ•ด์•ผ ํ•  ๋•Œ ํŠนํžˆ ํž˜์„ ๋ฐœํœ˜ํ•ฉ๋‹ˆ๋‹ค.

์ œ๋„ค๋ฆญ ์ œ์•ฝ์ด ๋„ˆ๋ฌด ๋ณต์žกํ•ด์งˆ ๋•Œ๋Š” ์–ด๋–ป๊ฒŒ ํ•˜๋‚˜์š”?

ํƒ€์ž… ๋ณ„์นญ์œผ๋กœ ์ œ์•ฝ์„ ๋ถ„๋ฆฌํ•ด ๊ฐ€๋…์„ฑ์„ ๋†’์ด์„ธ์š”.

type ValidKey<T> = keyof T;
type ValidValue<T, K extends ValidKey<T>> = T[K];

function update<T, K extends ValidKey<T>>(
  obj: T,
  key: K,
  value: ValidValue<T, K>
): void {
  obj[key] = value;
}

ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด์„ธ์š”

์ œ๋„ค๋ฆญ๊ณผ keyof๋Š” ํƒ€์ž… ์•ˆ์ „์„ฑ๊ณผ ์ฝ”๋“œ ํ’ˆ์งˆ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ž‘์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ถ€ํ„ฐ ์ ์šฉ ๋ฒ”์œ„๋ฅผ ๋„“ํ˜€๋ณด์„ธ์š”. ์‹ค๋ฌด์—์„œ ๊ฐ์ฒด ์†์„ฑ์— ์ ‘๊ทผํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด, ๊ทธ๊ณณ์ด ์ œ๋„ค๋ฆญ๊ณผ keyof๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ข‹์€ ์‹œ์ž‘์ ์ด์—์š”. ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค๊ฐ€ โ€œ์ด ์†์„ฑ์ด ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์‹ ์ด ์•ˆ ๋œ๋‹คโ€๋ผ๊ณ  ๋А๋‚€๋‹ค๋ฉด ๋ฐ”๋กœ ๊ทธ๋•Œ๊ฐ€ ์ œ๋„ค๋ฆญ ์ œ์•ฝ์„ ์ถ”๊ฐ€ํ•  ํƒ€์ด๋ฐ์ž…๋‹ˆ๋‹ค. TypeScript์˜ ํƒ€์ž… ์‹œ์Šคํ…œ์ด ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ๋” ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค„ ๊ฑฐ์˜ˆ์š” :)

References

TypeScript generic๊ณผ keyof๋กœ ํƒ€์ž… ์•ˆ์ „์„ฑ ๋†’์ด๊ธฐ