[Typescript] 04. 제네릭
포스트
취소

[Typescript] 04. 제네릭

Generic Function

만약 당신이 Java를 익숙하게 사용하는 개발자라면 이 섹션은 이해하기 정말 쉬울 것이다. 다른 언어에서 흔히들 Generic이라고 부르는 것과 동일하기 때문이다.
예를 들어, 당신이 Stack 자료구조를 직접 구현한다고 해보자.
Stack에는 정말로 많은 Type의 데이터가 들어간다. Number String Boolean와 같은 모든 유형을 포함해야 한다.

class Stack {
  private data = [];
  public push(item) {
    this.data.push(item);
  }
  public pop() {
    return this.data.pop();
  }
}

물론 이런 형태로 작성할 수는 있겠으나, 우리가 원하는 Typescript의 형태를 띄려면 각 MethodParamterReturn Type을 정의해야 한다.
만약 제네릭이 없다면

class NumberStack {
  private data: number[] = [];
  public push(item: number) {
    this.data.push(item);
  }
  public pop(): number {
    return this.data.pop();
  }
}
class StringStack {
  private data: string[] = [];
  public push(item: string) {
    this.data.push(item);
  }
  public pop(): string {
    return this.data.pop();
  }
}
/// ...

이런 식으로 모든 유형에 대응하는 StackClass를 정의해야 할 것이다.
이건 사실 말이 안되므로, 제네릭을 사용해서 구현을 하면 아래와 같이 표현할 수 있다.

class Stack<T> {
  private data: T[] = [];
  public push(item: T) {
      this.data.push(item);
  }
  public pop(): T | null {
      return this.data.pop() || null;
  }
}

class 이름 뒤에 <T>가 추가 되었다.
이는 Type을 받을 수 있는 Type Variable이라고 불린다. 제네릭 타입의 객체를 사용할 때는 아래와 같이 사용하면 된다.

1
const stack: Stack<number> = new Stack<number>();

이렇게 선언하면 number타입으로 구성 된 Stack 클래스를 사용할 수 있다.

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Stack<T> {
    private data: T[] = [];
    public push(item: T) {
        this.data.push(item);
    }
    public pop(): T | null {
        return this.data.pop() || null;
    }
}

const stack = new Stack<number>();
stack.push(123);
console.log(stack.pop()); // 123
console.log(stack.pop()); // null

두 개 이상의 Type Variable

Type Variable은 여러개를 선언할 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Stack<T, U> {
  private data: [T, U][] = [];
  public push(item: [T, U]) {
    this.data.push(item);
  }
  public pop(): [T, U] | null {
    return this.data.pop() || null;
  }
}

const stack: Stack<number, string> = new Stack<number, stirng>();
stack.push([123, 'hello']);
console.log(stack.pop()); // [123, 'hello']
console.log(stack.pop()); // null

Type 상속

가독성 측면에서 쓸 일이 진짜 없을 것 같지만 가능은 하다고 하니 알아보겠다.

1
2
3
4
5
function getFirst<T extends Stack<U>, U>(container: T): U {
  const item = container.pop();
  container.push(item);
  return item;
}
1
2
getFirst<Stack<number>, number)(numberStack);
getFirst<number, number>(1); // Type 'number' does not satisfy the constraint 'Stack<number>'.

참고

DailyEngineering - TypeScript: 제네릭(Generic)

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.