TS generic

space's pace·2022년 7월 1일
0

프론트엔드

목록 보기
14/15

제네릭은 Java 등의 정적 타입 언어를 사용하던 사람에게는 익숙한 단어일지도 모르겠다. 그러나 JavaScript를 사용해왔던 개발자에게는 그렇지 않다.

제네릭은 어떠한 클래스 혹은 함수에서 사용할 타입을 그 함수나 클래스를 사용할 때 결정하는 프로그래밍 기법을 말한다. Java나 C++ 등의 정적 타입 언어에서는 함수 및 클래스를 선언하는 시점에서 매개변수 혹은 리턴 타입을 정의해야하기 때문에 기본적으로는 특정 타입을 위해 만들어진 클래스나 함수를 다른 타입을 위해 재사용할 수가 없다. 때문에 제네릭을 통해 함수와 클래스의 범용적인 사용을 가능케 한다.

JavaScript는 원래 타입 선언이 필요하지 않고, 그렇기에 특정 타입을 위해 만들어진 클래스나 함수도 타입 에러를 런타임에서 일으킬 뿐이다. 코드를 실행시키기 전까지는 함수와 클래스가 모든 타입에 대응한다. 그렇기 때문에 JavaScript에서는 제네릭이란 말을 들을 일이 없다.

정적 타입 언어에서도 이렇게 특정 타입을 위해 만들어진 함수 혹은 클래스를 보다 범용적으로 재사용하기 위한 요구가 있기 때문에 제네릭이라는 프로그래밍 기법이 생긴 게 아닐까한다. TypeScript도 마찬가지로 정적 타입 언어이기 때문에, 기본적으로 타입을 정의한 함수 혹은 클래스는 모두 다른 타입에 재사용할 수 없다. 제네릭을 사용하지 않는다면 말이다.

제네릭을 사용하는 이유
제네릭을 유용하게 사용할 수 있는 경우로는 자료구조가 있다. 다음과 같이 스택 자료구조를 TypeScript로 구현한다고 가정하자.

class Stack {
  private data: any[] = [];

  contructor() {}

  push(item: any): void {
    this.data.push(item);
  }

  pop(): any {
    return this.data.pop();
  }
}

const stack = new Stack();
stack.push(1);
stack.push('a');
stack.pop().substring(0) // 'a'
stack.pop().substring(0) // Throw TypeError

그렇다고 자료형을 보장하기 위해 항상 number 타입의 변수만 받을 수 있도록 하면, 범용성이 떨어지게 된다.

물론 상속으로도 이를 처리할 수 있다.

class NumberStack extends Stack {
  constructor() {
    super();
  }

  push(item: number): void {
    super.push(item);
  }

  pop(): number {
    return super.pop();
  }
}```
profile
블로그 이사 준비중!

0개의 댓글