본문 바로가기

4주차

TypeScript Generic 타입 정복하자

 

 

안녕하세요! YB 김민정입니다 :) 

이번 4주차 과제하면서, 타입 문제 중 제너릭을 사용하면서 해결했던 것이 있었는데 

그 과정에서 제네릭 타입을 좀 더 깊이 톺아보면 좋을 것 같아서 알아보려 합니다 

 

제네릭(Generic) 이 뭘까?

 

 

우리는 '변수' 라는 저장소를 사용하기 때문에, 변할 수 있는 것을 다룬다. 

근데 우리가 배운 타입은 number, string, undefined 등 고정되어 있다.

따라서 타입을 직접적으로 고정된 값으로 명시하지 말고 '변수' 를 통해 언제든지 변할 수 있는 타입을 통해 보다 유연하게 코딩할 수 있는 장치가 필요한데, 그것이 바로 '제네릭(generic)' 타입이다.

-> 간단하게 말하자면.. 타입을 변수화 한 것이다!

 

 

빠르게 코드로 톺아보자. 

 

function identity(a: number , b:number): number {
  return a + b;
}

 

해당 코드는 숫자를 덧셈하는 함수이다.

근데 우린 숫자를 더하기도 하지만 String 을 더하고 싶다면?

 

 

function identity(a: string , b:string): string {
  return a + b;
}

 

이렇게 구현할 것이다. 

 

 

이 방법을 좀 더 확장시켜서 

 

function add(x: string | number, y: string | number): string | number {
   return x + y;
}

add(1, 2); // 3
add('hello', 'world'); // 'helloworld'

 

이렇게 표현한다면, 넘버와 스트링 두 타입을 동시에 다뤄서 유니온 타입을 통해 간단하게 구성이 가능하다. 

하지만 여기서는 함정이 있다.

x : string, y : string 혹은 x : number, y : number 를 예상하고 구현한 것이지만,

x : string, y : number 혹은 x : number, y : string 도 될 수 있다는 함정이 있다. 

 

이걸 어떻게 해결할까?

 

함수의 오버로딩 등 해결 방법이 있긴 하지만, 이것 또한 가독성 관점에서 문제가 있다.

 

이런 관점에서 나온 것이 " 제네릭 " 인 것이다.

 

function add<T>(x: T, y: T): T { 
   return x + y;
}

add<number>(1, 2); 
add<string>('hello', 'world'); // 'helloworld'

 

다음과 같이 T 변수를 지정함으로써, 코드에 선언한 타입을 변수화 해서 나중에 타입을 정하는 식으로 유연하게 구성이 가능하다. 

 

 

 

 

Generic 타입에 제약조건 달기

 

선언하는 함수의 parameter 에 제약 조건을 달고 싶으면

"extends" 키워드를 사용한다. 

function doubleArray<T extends any[]> (input: T){
    return [...input,...input];
    }

 

 

 

두 개 이상의 타입 변수를 제너릭으로 선언하고 싶다면

 

function toPair<T, U>(a: T, b: U): [ T, U ] {
    return [a, b]
}

 

제네릭 함수나 클래스에서는 두개 이상의 타입 변수도 사용 할 수 있다.

원래는 <T> 만 사용하였다면 <T, U> 두 가지의 타입 변수로 선언 할 수 있다.

 

 

toPair<string, number>('1',1);

-> 이렇게 부르는 게 가능해진다.