함수 혹은 클래스를 정의하는 시점에 매개변수나 반환값의 타입을 선언해야한다.
그러나, 함수나 클래스를 정의할 때 매개변수나 반환값 타입을 선언하기 힘든 경우가 있다.
이때, 제네릭은 한 번의 선언으로 다양한 타입을 재사용할 수 있다.
제네릭은 정리해도 사실 잘 모르겠다..
다시 공부하고 정리해서 업데이트 해야겠다...!
class Queue {
protected data: any[] = [];
push(item: any){
this.data.push(item);
}
pop() {
return this.data.shift();
}
}
const queue = new Queue();
queue.push(0);
queue.push('1'); // 실수
console.log(queue.pop().toFixed()); // 0
console.log(queue.pop().toFixed()); // RUNTIME ERROR
any[ ]
타입이다.any[ ]
타입은 어떤 타입 요소도 가질 수 있는 배열이다.any[ ]
타입은 배열 요소의 타입이 모두 같지 않다.number
타입만을 포함하는 배열이라는 기대하에, Number.prototype.toFixed
를 사용했다.number
타입이 아닌 요소의 경우, 런타임 에러가 발생한다.class Queue {
protected data: any[] = [];
push(item: any){
this.data.push(item);
}
pop(){
return this.data.shift();
}
}
// Queue 클래스를 상속하여 number 타입 전용 NumberQueue 클래스를 정의
class NumberQueue extends Queue{
// number 타입의 요소만을 push한다
push(item: number){
super.push(item);
}
pop(): number{
return super.pop();
}
}
const queue = new NumberQueue();
queue.push(0);
// 의도하지 않은 실수를 사전 검출 가능
// error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
// queue.push('1');
queue.push(+'1'); // 실수를 사전에 인지하고 수정 가능. +를 붙이면 num로 인식
console.log(queue.pop().toFixed()); // 0
console.log(queue.pop().toFixed()); // 1
NumberQueue
클래스를 정의하면, number 타입 이외의 요소가 push 되었을 때, 런타임 이전에 에러
를 사전에 감지할 수 있다.class Queue<T>{
protected data: Array<T> = [];
push(item: T) {
this.data.push(item);
}
pop(): T | undefined {
return this.data.shift();
}
}
// number 전용 Queue
const numberQueue = new Queue<number>();
numberQueue.push(0);
// numberQueue.push('1'); // 의도하지 않은 실수를 사전 검출 가능
numberQueue.push(+'1'); // 실수를 사전 인지하고 수정할 수 있다.
// ?. => optional chaining
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining
console.log(numberQueue.pop()?.toFixed()); // 0
console.log(numberQueue.pop()?.toFixed()); // 1
console.log(numberQueue.pop()?.toFixed()); // undefined
// string 전용 Queue
const stringQueue = new Queue<string>();
stringQueue.push('hello');
stringQueue.push('world');
console.log(stringQueue.pop()?.tpUpperCase()); // HELLO
console.log(stringQueue.pop()?.toUpperCase()); // WORLD
console.log(stringQueue.pop()?.toUpperCase()); // undefined
// 커스텀 객체 전용 Queue
const myQueue = new Queue<{name: string, age: number}> ();
myQueue.push({name: 'Olivia', age: 29});
myQueue.push({name: 'Lee', age: 29});
console.log(myQueue.pop()); // {name : 'Olivia', age: 29}
console.log(myQueue.pop()); // {name : 'Lee', age : 29}
console.log(myQueue.pop()); // undefined
T
는 제네릭을 선언할 때 관용적으로 사용되는 식별자로, Type Parameter
라고 한다.T
는 Type
의 약자로 반드시 T
를 사용하지 않아도 된다.function reverse<T>(itmes: T[]): T[]{
return items.reverse();
}
function reverse<T>(items: T[]): T[] {
return items.reverse();
}
const arg = [1, 2, 3, 4, 5];
// 인수에 의해 타입 매개변수가 결정된다.
const reversed = reverse(arg);
console.log(reversed); // [5, 4, 3, 2, 1]
function reverse<T>(items: T[]): T[] {
return items.reverse();
}
const arg = [{ name: 'Olivia' }, { name: 'Lee' }];
// 인수에 의해 타입 매개변수가 결정된다.
const reversed = reverse(arg);
console.log(reversed); // [ { name: 'Lee' }, { name: 'Olivia' } ]