logo
Search검색어를 포함하는 게시물들이 최신순으로 표시됩니다.
    Table of Contents
    [TS] 제네릭

    이미지 보기

    [TS] 제네릭

    • 22.06.17 작성

    • 읽는 데 5

    TOC

    제네릭(Generics)

    제네릭이란?

    재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징

    한 가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트 생성에 사용


    // JavaScript
    function logText(text) {
      console.log(text);
      return text;
    }
    
    logText('Hello');
    logText(10);
    logText(true);
    
    • JS 문법의 경우 위와 같은 함수에서는 어떤 것이든 인자로 사용 가능

    // TypeScript
    function logText<T>(text: T): T {
      console.log(text);
      return text;
    }
    
    logText<string>('Hello');
    
    • TS의 generic을 활용하면 함수를 호출할 때 type을 정의하겠다는 약속
    • 함수를 추상화해서 더 다양한 type에서 사용 가능

    image
    • 함수 호출에서 type을 정의하면 해당하는 type의 전달과 출력이 type으로 지정

    기존 TS 함수의 중복 선언

    function logText(text: string) {
      console.log(text);
      return text;
    }
    
    function logNumber(num: number) {
      console.log(num);
      return num;
    }
    
    logText('a')
    logNumber(10)
    
    • 기존 TS 문법은 type에 따라 함수를 중복 정의 해야한다.
    • 유지보수 차원에서 좋지 않음

    유니온 타입을 이용한 선언 방식 문제점

    function logText(text: string | number) {
      console.log(text);
      return text;
    }
    

    문제점1. 지정된 여러 type이 공통으로 가지는 method에서만 preview 지원

    image

    문제점2. 한 가지 타입에서만 존재하는 메서드 사용 불가

    image
    • 해당 함수의 결과값은 union type이므로 한 가지 type에서만 지원하는 메서드 사용 불가

    제네릭의 장점과 타입 추론에서의 이점

    function logText<T>(text: T): T {
      console.log(text);
      return text;
    }
    
    const str = logText<string>('a')
    str.split('')
    
    const num = logText<number>(10)
    num.toLocaleString()
    
    • generic을 통한 type 정의를 통해 return된 값을 변수로 지정
    • 이 변수는 각 type에서 지원하는 method 사용 가능
    image

    인터페이스에 제네릭 선언

    interface Dropdown<T> {
      value: T;
      selected: boolean;
    }
    
    const obj1: Dropdown<string> = { value: 'abc', selected: false };
    const obj2: Dropdown<number> = { value: 10, selected: false };
    

    제네릭의 타입 제한

    function logTextLength<T>(text: T): T {
      console.log(text.length);
      return text;
    }
    
    logTextLength('hi');
    
    • 함수 내부에서 인자의 메서드 사용은 인자의 type마다 다르다.
    • generic에서 type은 호출 때 정의되므로, 함수 작성 시에는 오류 발생
    image

    힌트를 주자!

    • text는 length를 셀 수 있는 애라는 것을 알린다!
    • text는 배열이라고 가정
    function logTextLength<T>(text: T[]): T[] {
      console.log(text.length);
      text.forEach(function (text) {
        console.log(text);
      })
      return text;
    }
    
    logTextLength<string>(['hi', 'abc']);
    
    • 실제 인자도 Array 형태로 전달해야 한다.

    제네릭의 타입 제한2 : 정의된 타입 이용

    interface LengthType {
      length: number;
    }
    
    function logTextLength<T extends LengthType>(text: T): T {
      text.length;
      return text;
    }
    
    logTextLength('abcdef');
    logTextLength(['a', 'b', 'c', 'd'])
    logTextLength({ length: 10 })
    logTextLength(10);
    
    • 정의될 Type은 length 속성/메서드를 가진 LengthType의 상속을 받는 type이 된다.
    • T type은 LengthType에 추가로 정의
    image

    제네릭의 타입 제한3 : keyof 이용

    interface ShoppingItem {
      name: string;
      price: number;
      stock: number;
    }
    
    function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T {
      return itemOption;
    }
    getShoppingItemOption('name');
    

    interface의 key들 중 하나를 인자로 사용


    Promise를 이용한 API 함수 타입 정의

    function fetchItems(): Promise<string[]> {
      let items = ['a', 'b', 'c'];
      return new Promise(function (resolve) {
        resolve(items);
      })
    }
    fetchItems();
    

    enum을 이용한 타입 정의

    findContactByPhone(phoneNumber: number, phoneType: string): Contact[] {
      return this.contacts.filter(
        contact => contact.phones[phoneType].num === phoneNumber
      );
    }
    

    이런 함수의 경우 인자로 phoneType을 받는다.

    findContactByPhone('Homee');
    

    그런데 이런 경우 오타를 방지할 수 없기 때문에 아래와 같이 enum을 사용


    enum PhoneType {
      Home = 'home',
      Office = 'office',
      Studio = 'studio',
    }
    
    findContactByPhone(PhoneType.Home);
    

    오타에 대한 에러를 바로 확인 가능

    profile

    FE Developer 박승훈

    노력하는 자는 즐기는 자를 이길 수 없다