성장, 그리고 노력

부족하더라도 어제보다 더 잘해지자. 노력은 절대 배신하지 않는다.

Typescript

[TypeScript] 타입스크립트 제네릭

제이콥(JACOB) 2019. 12. 8. 22:41

Typescript Generics

앞써한 포스팅에서 이미 any타입으로 타입을 느슨하게 만드는 법에 대해서는 공부하였다. 하지만, 문제가 있었다. any의 경우 타입 안정성이 떨어져서 의도치 않는 결과가
나올 수 있고, 그렇다고 한가지 타입으로만 정의하면 지정된 타입 이외에는 다른 타입을 받을 수 없기 때문에 고민이었다.

이 문제를 해결하기 위해 등장한 것이 제네릭(generic) 이다. 만약 다른 언어를 사용해봤다면 한번쯤은 들어봤을 문법이긴 하다. 사용법은 크게 다르지 않으며, 천천히 살펴보도록 하겠다.

제네릭 특징

제네릭은 다음과 같은 특징이자 장점을 가지고 있다.

  • 컴파일시 타입 안정성을 보장한다.
  • 캐스팅 관련 코드를 제거할 수 있다.

일단 예시 코드를 보면서 조금 더 상세하게 보겠습니다.

function add<T>(a: T, b: T){
  return Number(a) + Number(b);  // T + T는 연산이 되지 않습니다.  
}

let a = 2;
let b = 3;

let result = add<number>(a, b); 
console.log(result);

여기서 <T>가 타입 매개변수(type argument)라고 합니다(또는 제네릭 타입 변수). T 대신 다른 문자를 써도 상관 없습니다.
그리고 먼저 선언한 타입 매개변수를 기준으로 컴파일시 타입 바인딩(type binding)을 통해 타입 변수(a,b)의 타입이 정해집니다.
하지만 여기서 궁금증이 생깁니다. Number(a) 이렇게 생긴 불필요한 캐스팅 코드가 들어가게 됩니다.

이를 해결하는 방법은 2가지가 있습니다.

타입 상속을 이용한 방법

특정 타입(기본타입, 클래스, 인터페이스 등)을 <T extends number>의 방식으로 상속합니다.

function add<T extends number>(a: T, b: T){ // 유니온 타입으로 할 수도 있습니다. <T extends number|string>
  return a + b;
}

이렇게 선언하면 의 타입을 제한하는 형태를 의미하기도 합니다.

오버로드를 이용한 방법

함수를 오버로딩하면 T+T의 매개변수 연산이 가능합니다.

function add<T>(a: T, b: T): T;
function add<T>(a: any, b: any){ // 유니온 타입으로 할 수도 있습니다. <T extends number|string>
  return a + b;
}

2개 이상의 타입 변수를 선언

1개 선언하듯이 2개를 연달아 선언해 주면 됩니다.

let arr = {};

function set<T, T2>(a: T, b: T2): T;
function set(key: any, value: any){
    return arr[key] = value;
}
set<string, string|number>("1", 1);
console.log(arr); // { '1': 1 }

function get<T, T2>(key: T): T2;
function get(key: any){
  return arr[key];
}

console.log(get<string, number | string>("1")); // 1

 

룩업 타입(Lookup type - keyof)

룩업 타입은 keyof로 속성을 포함하는 대상을 찾아서, 유니언 타입처럼 동작합니다.

  interface exLookup {
    ex1: number;
    ex2: number;
    ex3: number;
  }

  type useLookup = keyof exLookup;

만약 위와 같이 구현했다면, useLookup은 인터페이스 속성의 속성에 해당하는 "ex1", "ex2", "ex3" 값 중 하나의 속성명만 허용합니다.

  let real: useLookup = "ex2"; // 허용!

함수에서 전달받은 인자값을 받은 객체의 속성 값으로 제한하고 싶을때는 아래와 같이 설계하면 됩니다.

  function getItem<T, K extends keyof T>(object: T, key: K){
    return object[key];
  }
  let arr = {"넝":1, "뇽":2};
  console.log(getItem(arr, "뇽")); // 2
반응형