[TypeScript] Type Generic


1. Generic : ์ œ๋„ค๋ฆญ์ด๋ž€ ํƒ€์ž…์„ ๋งˆ์น˜ ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ

  • ์ œ๋„ค๋ฆญ์€ C#, Java ๋“ฑ์˜ ์–ธ์–ด์—์„œ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ ์ž์ฃผ ํ™œ์šฉ๋˜๋Š” ํŠน์ง•์ž…๋‹ˆ๋‹ค. ํŠนํžˆ, ํ•œ๊ฐ€์ง€ ํƒ€์ž…๋ณด๋‹ค ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ํƒ€์ž…์—์„œ ๋™์ž‘ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

1) ์ œ๋„ค๋ฆญ ํ™œ์šฉํ•˜๊ธฐ

  1. Generic ๊ธฐ๋ณธ ๋ฌธ๋ฒ• ์ •๋ฆฌ
  • V : value
  • T : type
  • K : key
  • E : element
function genericTest<T>(arg: T): T {
  return arg;
}

genericTest<string>("Hello World!");
genericTest("Hello World!"); // ํƒ€์ž… ์ถ”๋ก 

์‚ฌ์šฉ ์ด์œ 

  • ํƒ€์ž…์„ ๋ฏธ๋ฆฌ ์ง€์ •ํ•˜๊ฒŒ ๋˜๋ฉด ๋ฒ”์šฉ์„ฑ์ด ๋–จ์–ด์ง
  • any๋ฅผ ์“ฐ๋ฉด return ํƒ€์ž…๊ณผ parameter ํƒ€์ž…์„ ์•Œ ์ˆ˜ ์—†์Œ.

  1. ์ œ๋„ค๋ฆญ ํƒ€์ž… ๋ณ€์ˆ˜(Generic Type Variables)
function genericTest<T>(arg: T): T {
  console.log(arg.length); // error: 'T' ํ˜•์‹์— 'length' ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.
  return arg;
}
/* T(ํƒ€์ž… ๋ณ€์ˆ˜)์— ๋Œ€ํ•œ ์„ธ๋ถ€์ ์ธ ๋ณ€์ˆ˜ ํƒ€์ž…์„ ์ง€์ • */

function genericTest<T>(arg: T[]): T[] {
    console.log(arg.length);
    return arg;
}

=> genericTest๋Š” ํƒ€์ž…๋ณ€์ˆ˜ T์™€ T ๋ฐฐ์—ด ์ธ์ˆ˜ arg๋ฅผ ์ทจํ•˜๊ณ  T ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜

  1. ์ œ๋„ค๋ฆญ ํƒ€์ž… (Generic Types)
function genericTest<T>(text: T): T {
    return text;
  }
  // #1
  let str: <T>(text: T) => T = genericTest;

  // #2
//   let str: {<T>(text: T): T} = genericTest;

=> #1,#2๋Š” ๊ฐ™์€ ์˜๋ฏธ์ž„.

  1. ์ œ๋„ค๋ฆญ ์ธํ„ฐํŽ˜์ด์Šค (Generic Interface)
interface IGenericTestFn {
  <T>(text: T): T;
}
function genericTest<T>(text: T): T {
  return text;
}
let myString: IGenericTestFn = genericTest;

T๋Š” ์ œ๋„ค๋ฆญ์„ ์„ ์–ธํ•  ๋•Œ ๊ด€์šฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์‹๋ณ„์ž๋กœย ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ(Type parameter)

/* ์ธํ„ฐํŽ˜์ด์Šค์— ์ธ์ž ํƒ€์ž…์„ ๊ฐ•์กฐ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ */

interface IGenericTestFn<T> {
  (text: T): T;
}
function genericTest<T>(text: T): T {
  return text;
}
let myString: IGenericTestFn<string> = genericTest;

  1. ์ œ๋„ค๋ฆญ ํด๋ž˜์Šค (Generic Classes)
interface Value<L,R> {
    callLeft: () => L;
    callright: () => R;
}

class Diary<L,R> implements Value<L,R> {
		//implements ํ‚ค์›Œ๋“œ๋Š” class์˜ interface์— ๋งŒ์กฑํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•  ๋•Œ ์‚ฌ์šฉ
		//implementsํ•œ interface์˜ ํƒ€์ž…์ด ์—†๋‹ค๋ฉด ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜
    constructor(private feeling: L, private shortWords: R){}
		//private์œผ๋กœ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ๋งŒ ์ฐธ์กฐ ๊ฐ€๋Šฅํ•˜๋‹ค.
    callLeft(): L {
        console.log(this.feeling);
        return this.feeling
    }

    callright(): R {
        console.log(this.shortWords);
        return this.shortWords
    }
}

const yesterdayDiary: Value<string, string> = new Diary("Bad", "๋ชธ์ด ์•„ํ”„๋„ค์š”");
//์ƒ์„ฑ์ž ํ˜ธ์ถœ
console.log(yesterdayDiary);

const todayDiary = new Diary({"happy": 10}, "๋กœ๋˜ ๋‹น์ฒจ");
//์ƒ์„ฑ์ž ํ˜ธ์ถœ
console.log(todayDiary);

=> ๊ฒฐ๊ณผ๊ฐ’

Diary { feeling: 'Bad', shortWords: '๋ชธ์ด ์•„ํ”„๋„ค์š”' }
Diary { feeling: { happy: 10 }, shortWords: '๋กœ๋˜ ๋‹น์ฒจ' }


  1. ์ œ๋„ค๋ฆญ ์ œ์•ฝ์กฐ๊ฑด (Generic Constraints)
interface Info {
  feeling: string;
}

function call<T extends Info>(today: T): T {
  console.log(today.feeling);
  return today;
}

call({ feeling: "good" });
call("good"); // Argument of Type 'string' is not assignable to paramerter of type 'Info'

๋ฌธ์ž์—ด ํƒ€์ž…์˜ ์ธ์ˆ˜๋Š” Info ํƒ€์ž…์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ํ• ๋‹นํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜ค๋ฅ˜

Info ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™•์žฅํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์—, ์ •์˜๋œ ์ธํ„ฐํŽ˜์ด์Šค์™€ ์ผ์น˜ํ•ด์•ผํ•จ.

any๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๋ฉด ์ €์žฅํ•˜๊ณ  ์žˆ๋Š” ์ž๋ฃŒ์˜ ํƒ€์ž…์ด ๋ชจ๋‘ ๊ฐ™์ง€ ์•Š๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์ƒ๊ธฐ๋Š”๋ฐ, ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ตณ์ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์“ธ ํ•„์š”๊ฐ€ ์—†๋‹ค