클래스나 함수에서 타입을 미리 결정짓지 않고 그것을 사용할 때 타입을 결정해 사용하는 것을 말합니다.
let list = [];
const Add = (x: number) => {
list.push(x);
};
Add(10);
console.log(list[0]);
위 예제는 Add함수를 통해 list에 요소를 추가한 뒤 이를 보여주는 함수입니다. 그런데 Add를 보면 number만 받을 수 있습니다. 만약 string이나 기타 다른 형식이 다뤄져야 한다면 그에 맞는 형식의 배열과 변수를 모두 만들어야 한다는 뜻이 되지만 제네릭을 이용해 문제를 해결할 수도 있습니다.
let list = [];
function Add<T>(x: T) {
list.push(x);
};
Add(10);
Add('abc');
console.log(list[1]);
함수를 제네릭형태로 만들려면 함수명 옆에 <T>와 같이 제네릭 사용을 위한 이름을 부여하고 같은 이름을 사용해 매개변수 또는 반환 형식을 지정해 주면 됩니다. 예제에서는 제네릭 이름을 T로 하였고 때문에 매개변수를 받는 부분에서 데이터 타입을 T로 정의하였습니다.
이렇게 되면 Add()함수를 호출할 때 특정 타입이 아닌 다양한 타입을 넘겨줄 수 있게 됩니다.
클래스의 경우에도 동일한 목적으로 제네릭이 사용될 수 있는데
class ReturnData {
constructor (private v: number) {
};
GetValue(): number {
return this.v;
};
};
const rd = new ReturnData(10);
console.log(rd.GetValue());
예제에서의 ReturnData클래스의 경우 생성자를 통해 특정 값을 전달받고 GetValue() 함수를 통해 그 값을 그대로 전달받고 있습니다. 다만 이 클래스는 number형식만 받고 내보낼 수 있도록 되어 있는데 물론 이런 경우에도 제네릭을 사용해 데이터를 다양화시킬 수 있습니다.
class ReturnData<T> {
constructor (private v: T) {
};
GetValue(): T {
return this.v;
};
};
const rd = new ReturnData('abc');
console.log(rd.GetValue());
클래서는 클래스명옆에 <T>처럼 제네릭을 지정합니다. 생성자 매개변수가 여러 개인 경우라도 그만큼 <A, B, C...> 와 같이 제네릭을 지정해 주면 됩니다.
참고로 제네릭은 함수나 클래스에 한정되지 않고 데이터를 다루는 거의 모든곳에 적용할 수 있습니다. 아래 예제는 인터페이스에 제네릭을 적용한 예이며
interface inter<T> {
sum: (T) => T;
};
type에서도 제네릭이 사용될 수 있습니다.
type Car = {
color: string;
speed?: number;
};
type CarT<T> = {
[K in keyof T]: T[K];
};
type Truck = CarT<Car>;
에제는 CarT type에 <T>를 적용해 특정 type의 키와 타입을 그대로 가져오는 동작을 구현한 것입니다.
그런데 제네릭이라고 하더라도 타입을 제한해야 하는 경우가 종종 있습니다.
class ReturnData<T extends number | string> {
constructor (private v: T) {
};
GetValue(): T {
return this.v;
};
};
타입제한은 extends를 사용해 타입을 지정해 주면 됩니다. 위 에제대로 라면 생성자로는 number나 string타입의 데이터만 넘겨줄 수 있습니다.
interface IData {
name: string;
age: number;
};
const mydata: IData = {
name: 'kim',
age: 16
};
class ReturnData<T extends IData> {
constructor (private v: T) {
};
GetValue(): T {
return this.v;
};
};
const rd = new ReturnData(mydata);
console.log(rd.GetValue().name);
또한 특정 객체에 대해서는 extends와 keyof를 결합해 특정 객체의 키로 제한할 수도 있는데
const mydata: IData = {
name: 'kim',
age: 16
};
function GetValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
};
console.log(GetValue(mydata, 'name'));
예제와 같이 extends keyof라고 하면 해당 K는 T객체의 키로 한정하는 것이 됩니다. 리턴되는 결과 또한 T에서 [K]를 사용해 T객체의 키를 지정하고 있는데 이는 객체의 키에 해당하는 값의 반환한다는 의미입니다.
'Web > TypeScript' 카테고리의 다른 글
[TypeScript] Visual Studio에서 TypeScript사용하기 (0) | 2022.05.06 |
---|---|
[TypeScript] tsconfig.json (0) | 2021.03.13 |
[TypeScript] 객체지향 프로그래밍 (0) | 2021.03.11 |
[TypeScript] 데이터 타입 (0) | 2021.03.10 |
[TypeScript] 개요및 준비 (0) | 2021.03.10 |