ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

TypeScript

๐Ÿ“— Generics

yunieyunie 2022. 12. 22. 10:36

๐Ÿ”Ž Generics, Any ์™€ ๋‹ค๋ฅธ ์ 

๋ณดํ†ต์˜ ํ•จ์ˆ˜๋Š” ๋“ค์–ด์˜ค๋Š” ์ธ์ž์™€ ๋‚˜๊ฐ€๋Š” ๋ฆฌํ„ด์˜ ํƒ€์ž…์ด ์ผ์ •ํ•œ ๊ทœ์น™์„ ์ด๋ฃจ๋ฉฐ ๊ฐ™์€ ๋กœ์ง์ด ๋ฐ˜๋ณต๋œ๋‹ค.

function helloString(message: string): string { 
      return message;
  }
  function helloNumber(message: number): number { 
      return message;
  }

๋ฐ˜๋ณต์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ํƒ€์ž…์„ ์ธ์ž๋กœ ๋ฐ›๊ณ  ๋ฆฌํ„ดํ•  ์ˆ˜ ์žˆ๋Š” any๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํƒ€์ž…์ด ์„œ๋กœ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

function hello(message: any): any { 
      return message;
  }
  console.log(hello('Mark').length); // any์˜ length๋„ any๋กœ ์ถ”๋ก 
  console.log(hello(38).length); // ์—๋Ÿฌ๊ฐ€ ์•„๋‹Œ undefined ์ถœ๋ ฅ

hello ์˜ ๋ฆฌํ„ด์ด any ์ด๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž… ํ—ฌํผ๊ฐ€ ์ œ๋Œ€๋กœ ๋˜์ง€ ์•Š๋Š”๋‹ค.
์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ธ์ž ํƒ€์ž…์„ ๋ณ€์ˆ˜๋กœ ํ™œ์šฉํ•ด ๋ฆฌํ„ด ํƒ€์ž…๊ณผ ๊ฐ™์ด ์—ฐ๊ด€์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด generic์ด๋‹ค.
T๋Š” ํƒ€์ž…์„ ์˜๋ฏธ, ํ•ด๋‹น ํ•จ์ˆ˜ ๋‚ด์—์„œ T์˜ ํƒ€์ž…์„ ๊ธฐ์–ตํ•˜์—ฌ Mark๋ฅผ ๋„ฃ์œผ๋ฉด string์œผ๋กœ ๊ธฐ์–ตํ•œ๋‹ค.

function helloGeneric<T>(message: T): T { 
      return message;
  }

  console.log(helloGeneric('Mark')); //Mark
  console.log(helloGeneric('Mark').length); //4
  console.log(helloGeneric(36).length); //์—๋Ÿฌ

๐Ÿ“ข Generics Basic

  • ๋ฐฉ๋ฒ• 1. Generic ํƒ€์ž…์„ ์ง์ ‘ ์ง€์ •
  • ๋ฐฉ๋ฒ• 2. Generic ํƒ€์ž…์„ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  T๋ฅผ ์ถ”๋ก 
function helloBasic<T>(message: T): T { 
      return message;
  }

  //๋ฐฉ๋ฒ•1. 
  helloBasic<string>('Mark'); //<string>๋ฅผ ํ•ด์ฃผ๋ฉด ()์•ˆ์— string ๋งŒ ๋“ค์–ด๊ฐ€์•ผํ•จ

  //๋ฐฉ๋ฒ•2.
  helloBasic(38);
  helloBasic<number>('38'); //์—๋Ÿฌ

๋ณ€์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๋„ฃ์„ ์ˆ˜๋„ ์žˆ๋‹ค.

function helloBasic<T, U>(message: T, comment: U): T { 
      return message;
  }

  //๋ฐฉ๋ฒ•1. 
  helloBasic<string, number>('Mark',30); //<string>๋ฅผ ํ•ด์ฃผ๋ฉด ()์•ˆ์— string ๋งŒ ๋“ค์–ด๊ฐ€์•ผํ•จ

  //๋ฐฉ๋ฒ•2. 
  helloBasic(38, 39);

๐Ÿ†š Generics Array & Tuple

๊ฐ ์ƒํ™ฉ์— ๋งž์ถฐ array์™€ tuple์„ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ง€์ •ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

//array
  function helloArray<T>(messages: T[]): T { 
      return messages[0]; 
  }
  console.log(helloArray(['Hello', 'World'])); // Hello
  console.log(helloArray(['Hello', 1])); // ํƒ€์ž…์ด ๋‹ค๋ฅด๋ฏ€๋กœ ๋ฆฌํ„ดํƒ€์ž…์ด string์ด๋‚˜ number๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.
//tuple
  function helloTuple<T, K>(messages: [T, K]): T { 
      return messages[0];
  }

  console.log(helloTuple(['Hello', 'World'])); // Hello
  console.log(helloTuple(['Hello', 1])); // [string, number]์ด์–ด์„œ string์ด ์ž˜ ์ถœ๋ ฅ๋จ.

๐ŸŽฏ Generics Function

๊ทธ๋™์•ˆ ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด generic์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ์ด๋ฒˆ์—” ํ•จ์ˆ˜์˜ ํƒ€์ž…๋งŒ ์„ ์–ธํ•ด๋ณด์ž.
type alias ๋ฐฉ์‹๊ณผ interface ๋ฐฉ์‹์ด ์žˆ๋‹ค.

//type alias
  type HelloFunctionGeneric = <T>(message: T) => T;

  const helloFunction: HelloFunctionGeneric = <T>(message: T): T => { 
      return message;
  };
  console.log(helloFunction<string>('Hello').length); //5
//interface
  interface HelloFunctionGeneric1 {
      <T>(message: T): T;
  }

  const helloFunction1: HelloFunctionGeneric = <T>(message: T): T => { 
      return message;
  };
  console.log(helloFunction1<string>('Hello').length); //5

๐Ÿ›’ Generics Class

class์•ˆ์—์„œ generic์„ ์‚ฌ์šฉํ•ด๋ณด์ž.

class Person<T> { //T์˜ ์œ ํšจ๋ฒ”์œ„๋Š” class ์ „์ฒด
      private _name: T;

      constructor(name: T) { 
          this._name = name;
      } 
  }

  new Person('Mark');
  new Person<string>(38); //์—๋Ÿฌ

๋ณ€์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ์ง€์ •ํ•ด๋ณด์ž.

class Person7<T, K> { 
      private _name: T; 
      private _age: K;

      constructor(name: T, age: K) { 
      this._name = name;
      this._age = age; 
      }
  }

  new Person7('Mark', 38);

๐ŸŽซ Generics with extends

generic์œผ๋กœ ์‚ฌ์šฉํ•  ๋•Œ๋Š” extends๊ฐ€ ์ƒ์†์˜ ๊ฐœ๋…๊ณผ๋Š” ์•ฝ๊ฐ„ ๋‹ค๋ฅด๋‹ค.
extends๋กœ ํƒ€์ž…์— ์ œ์•ฝ์„ ๊ฑธ์–ด์ฃผ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ์‚ฌ์šฉ์ž์˜ ์˜ค๋ฅ˜๋ฅผ ์ค„์ด๊ฒŒ ๋œ๋‹ค.
generic์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” extends๋„ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜์ž.

class PersonExtends<T extends string | number> { //string๊ณผ number๋งŒ ๊ฐ€๋Šฅ
      private _name: T;

      constructor(name: T) { 
          this._name = name;
      } 
  }

  new PersonExtends('Mark'); 
  new PersonExtends(38);
  new Person6(true); // T ๊ฐ€ string ๋˜๋Š” number๋ฅผ ์ƒ์†๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— boolean ์€ X

๐Ÿ”— keyof & type lookup system

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

  const person8: Person8 = { 
      name: 'Mark',
      age: 28 
  };

  function getProp(obj: Person8, key: "name" | "age"): string | number {
      return obj[key];
  }

  function setProp(obj: Person8, key: "name" | "age", value: string | number): void {
      obj[key] = value;
  }

getProp์™€ setProp์—์„œ name/age์„ ๋„ฃ์œผ๋ฉด string/number์ธ mark/28์ด ๋ฐ˜๋“œ์‹œ ๋‚˜์™€์•ผ ํ•˜๋Š”๋ฐ ๊ฒฐ๊ณผ๋Š” string ํ˜น์€ number์ด๋ฏ€๋กœ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.
์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € keyof ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž. keyof ๊ฐœ์ฒด = ๋ฌธ์ž์—ด ํ˜•ํƒœ์˜ key ๋ฅผ ๋œปํ•œ๋‹ค.

function getProp(obj: Person8, key: keyof Person8): Person8[keyof Person8] {
      return obj[key];
  }

  function setProp(obj: Person8, key: keyof Person8, value: string | number): void {
      obj[key] = value;
  }

๊ทธ๋Ÿฐ๋ฐ Person8[keyof Person8] = Person8["name" | "age"] = Person8["name"] | person8["age"] = string | number ์ด๋‹ค.
์•„์ง๋„ string ํ˜น์€ number๋ผ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํžˆ ์•ˆ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ด์ œ generic์„ ์‚ฌ์šฉํ•ด๋ณด์ž.
Person8์„ T๋กœ ๋ฐ”๊พธ๊ณ  K๋„ name๊ณผ age๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก extends๋กœ ์ •์˜ํ•ด์ค€๋‹ค.

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

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

  setProperty(person8, 'name', 'Anna');
  setProperty(person8, 'name', 27); //์—๋Ÿฌ
  getProperty(person8, 'name');
  getProperty(person8, 'fullname');//์—๋Ÿฌ

'TypeScript' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

๐Ÿ“— Classes  (0) 2022.12.19
๐Ÿ“’ Interfaces  (0) 2022.12.16
๐Ÿ“’ TypeScript Compiler  (0) 2022.12.15
๋Œ“๊ธ€