함수 / 클래스를 정의할 때 정의하는 시점에 매개변수나 반환값의 타입을 선언하기 어려울 경우가 있다.
예) 숫자만 들어가거나, 문자열만 들어가게 만들고 싶은 큐를 만들어야 할 경우를 만들려고 한다.
const n = [1,2,3,4]
const s = ['a','b','c']
class Queue {
protected data: any[] = [];
push(item: any) {
this.data.push(item);
}
pop() {
return this.data.shift();
}
}
queue = new Queue();
queue.push(1);
queue.push("a");
queue; // [1,'a'] 원하던 결과가 아니다.
이 와 같은 경우는 다시 NumberQueue 와 StringQueque 를 만들어 해결했어야 했다.
class NumberQueue extends Queue {
push(item: number) {
super.push;
}
pop(): number {
return super.pop();
}
}
하지만 이렇게 만들면 타입 별로 클래스를 상속받아 추가해야 하므로 좋은 방법은 아니다.
제네릭을 통해 문제를 해결할 수 있다.
class Queue<T> {
protected data: Array<T> = [];
push(item: T) {
this.data.push(item);
}
pop(): T | undefined {
return this.data.shift();
}
}
const nQueue = new Queue<number>();
const myQueue = new Queue<{ name: string; age: number }>();
제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시할 수 있다.
한번의 선언으로 다양한 타입에 재사용이 가능한 장점을 가진다.
'T' 는 Type parameter 로 제네릭을 선언할 때 관용적으로 사용되는 식별자이다.
function reverse<T>(items: T[]): T[] {
return items.reverse();
}
const arg = [1, 2, 3, 4];
const arg_rev = reverse(arg);
매개변수로 Array<number>
이 왔기 때문에 T = number이 된다.