Generics는 객체에 타입이 정해지지 않았을 때, 여러 타입에 대응하기 위해 사용한다. "여러 타입에 대응"한 다는 것은 객체의 확장성을 높혀주며, 재사용성을 높혀준다.
Generics 말고, 파라미터와 반환 값의 데이터 타입을 any
로 대응할 수 있다. 해당 방법에 대해서 알아보자.
//파라미터 데이터 타입 : any
//반환값 : any
export const fetchData = async (params: any): Promise<any> => {
//fetch...
};
const datas = fetchData({ url: 'http://localhost:8080/city', query: 'korea' });
위의 코드는 typescript에서 치명적인 단점을 보여준다. 우리가 typescript를 사용하는 이유는 타입을 지정하고, 반환값의 타입을 유추하기 위해서이다.
그러나 위의 코드에서 datas
의 데이터 타입은 any
로 나타나지면서, 우리는 fecth 후에 서버에서 받아진 데이터 타입을 유추할 수 없게 된다.
우리는 위와 같은 문제를 해결하기 위해 Generics를 사용한다. 사용 방법은 객체 명 옆에 <T>
를 사용하고 객체 내에서 타입을 T
값으로 명시해준다. T
는 type의 약자이다. 다른 문자를 사용해도 무방하다.
함수
와 class
에서 사용하는 방법은 아래와 같다.
interface dataT {
data: {
id: number;
name: string;
company: string;
}[];
}
export const fetchData = async <T1, T2>(params: T1): Promise<T2> => {
const res = await fetch(`${params}`);
return res.json();
};
const data = await fetchData<string, dataT>('http://localhost:8080/search?city=seoul');
Generics로 만들어주면 아래와 같이, IDE에서 반환값의 데이터 타입을 알 수 있다.
Generics가 없이, class를 만들게 되면 class마다 type에 대한 구분을 해줘야한다. 이렇게 되면 아래와 같이 반복되는 코드가 생기며, class의 재사용성이 떨어지게 된다.
class numberQueue {
list: number[] = [];
enqueue(item: number) {
this.list.push(item);
}
dequeue() {
return this.list.shift();
}
}
class stringQueue {
list: string[] = [];
enqueue(item: string) {
this.list.push(item);
}
dequeue() {
return this.list.shift();
}
}
const numberQ = new numberQueue();
const stringQ = new stringQueue();
numberQ.enqueue(0);
numberQ.enqueue('a'); // error!
numberQ.enqueue(1);
console.log(numberQ.dequeue()); // 0
console.log(numberQ.dequeue()); // 1
stringQ.enqueue('a');
stringQ.enqueue(1); // error!
stringQ.enqueue('b');
console.log(stringQ.dequeue()); // 'a'
console.log(stringQ.dequeue()); // 'b'
위와 같은 코드를 Generics를 사용해 반복되는 코드는 줄이고, 재사용성을 높혀보자.
class Queue<T> {
list: T[] = [];
enqueue(item: T) {
this.list.push(item);
}
dequeue() {
return this.list.shift();
}
}
const numberQ = new Queue<number>();
const stringQ = new Queue<string>();
interface Datas<T> {
list: T[];
}
const items: Datas<nubmer> = {
list: [1, 2, 3],
};
type Datas<T> = {
list: T[];
};
const datas: Datas<number> = {
list: [1, 2, 3],
};