타입스크립트 기초 제네릭 클래스 / 클래스 구조 재사용
타입스크립트 제네릭 클래스( TypeScript Generic Class)는
클래스 이름 뒤에 <T>와 같은 타입 매개변수를 선언하여
하나의 클래스 구조를 여러 데이터 타입에 재사용하는 방법이다.
class Box<T>처럼 클래스를 만든 뒤 Box<number>, Box<string>처럼 사용할 수 있다.
중복 클래스를 여러 개 만들 필요가 없으며, 재사용 가능한 코드를 작성할 수 있으며,
<T>를 임시로 표시하는 이름 정도로 볼 수 있다.
![]() |
| 타입스크립트 기초 제네릭 클래스 <T> 사용 클래스 구조 재사용 |
⊙ 타입스크립트 제네릭 클래스
타입스크립트( Typescript )의 제네릭(Generic)은 타입을 매개변수처럼 전달하는 기능이다.
만약, 일반 클래스를 만들고, 타입을 number로 설정하면 숫자만 사용할 수 있다.
class NumberBox {
value: number;
constructor(value: number) {
this.value = value;
}
}위의 코드는 숫자만 가능하며, 문자열을 저장하려면 별도의 클래스를 만들어야 한다.
제네릭을 사용하면 하나의 클래스로 해결할 수 있다.
class Box<T> {
value: T;
constructor(value: T) {
this.value = value;
}
}위의 코드에서 T는 타입 매개변수(Type Parameter)이다.
쉽개 비유하면
T는 아직 내용물이 정해지지 않은 상자에 붙여 놓은 빈 라벨이라고 생각하자.
![]() |
| 타입스크립트 제네릭 클래스 |
⊙제네릭 클래스 기본 문법
타입스크립트에서 사용하는 제네릭 클래스의 기본 문법은 다음과 같다.
클래스, 생성자, 메서드에 제네릭을 표시하는 <T>와 T를 설정했다.
class Box<T> {
value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}핵심은 세 곳이다.
class Box<T><T>는 이 클래스에서 사용할 타입을 나타낸다.
value: Tvalue의 타입을 T로 지정한다.
getValue(): T메서드가 반환하는 값도 같은 T 타입이다.
만약,
Box<number>를 만들면 클래스 내부의 T는 number가 되고,
Box<string>을 만들면 T는 string이 된다.
타입스크립트의 제네릭 클래스는 클래스 이름 뒤의 꺾쇠괄호 <> 안에 타입 매개변수를 선언하는 형태이다.
![]() |
| 제네릭 클래스 기본 문법 |
⊙ 제네릭 클래스 number와 string 사용
제네릭 클래스가 무엇인지, 사용법을 알았다.
단순히 클래스의 껍데기 정도로 생각하자.
제네릭 클래스를 사용하면 어떤 타입이든 공통된 형식의 클래스를 여러 개로 사용할 수 있다.
이번엔 하나의 제네릭 클래스를 사용하여 number, string 타입을 사용해 보기로 한다.
class Box<T> {
value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}
const numberBox = new Box<number>(100);
const stringBox = new Box<string>("Hello");
console.log(numberBox.getValue());
console.log(stringBox.getValue());제네릭 클래스 하나를 만들었지만,
전혀 다른 타입의 클래스로 사용할 수 있다.
위의 코드에서 제네릭 T 가 설정된 부분이 중요하며, T를 선언하는 방법에 따라 타입이 결정된다.
위의 결과에 대한 실행 결과는 다음과 같다.
![]() |
| 제네릭 클래스 number와 string 사용 |
![]() |
| 제네릭 클래스 number와 string 사용 |
⊙ 객체를 저장하는 제네릭 클래스 만들기
타입스크립트 제네릭 클래스는 숫자와 문자열뿐 아니라 객체 타입도 사용하여 객체 타입 데이터를 저장하여 사용할 수 있다.
코드를 보자.
class StorageBox<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
getAll(): T[] {
return this.items;
}
}객체 저장을 위한 제네릭 클래스의 사용법은 동일하다.
사용할 객체 타입을 만들어 보자.
interface User {
id: number;
name: string;
}
const userStorage = new StorageBox<User>();
userStorage.add({
id: 1,
name: "Kim"
});
userStorage.add({
id: 2,
name: "Lee"
});
console.log(userStorage.getAll());StorageBox<User>를 선언하는 순간 클래스의 제네릭 T는 User가 된다.
다만, 제네릭 클래스에 저장되는 객체의 형태는 같아야 하며,
다음처럼 구조가 다른 경우 타입 검사에서 오류가 발생한다.
userStorage.add({
id: 3
});User 타입에 필요한 name이 없으며, 객체의 구조가 다르기에 타입 검사에서 오류가 발생한다.
![]() |
| 객체를 저장하는 제네릭 클래스 만들기 |
⊙ extends 제네렉 타입 제한하기
타입스크립트 제네릭에 extends 키워드를 사용하면 타입을 제한할 수 있다.
이 기능은 다른 의미로 제네릭 제약조건( Generic Constraints )이라 한다.
타입스크립트 제네릭의 extends 는 클래스 내부에서 특정 프로퍼티나 메서드를 반드시 사용해야 할 때 유용하다.
코드를 보자.
interface HasId {
id: number;
}
class Repository<T extends HasId> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
findById(id: number): T | undefined {
return this.items.find(item => item.id === id);
}
}위의 코드를 보면, 이제 제너릭 T에는 최소한 다음의 구조가 존재해야 한다.
{
id: number;
}id 타입이 있는 다른 구조를 만들어 보자.
최소한의 구조에 id 가 있으며, 제네릭 클래스로 사용할 수 있다.
interface Product {
id: number;
name: string;
price: number;
}
const products = new Repository<Product>();만약, id가 없는 타입은 제약조건을 만족하지 못하며, 타입 검증 단계에서 에러가 발생한다.
![]() |
| extends 제네렉 타입 제한 |
⊙ 제네릭 클래스 주의할 점
타입스크립트의 제네릭을 뜻하는 단어 <T>의 T는 특별한 키워드는 아니다.
임의의 단어 또는 자신이 원하는 단어를 사용할 수도 있다.
아래의 코드를 보자.
본래의 경우 <T> 형태로 제네릭 클래스를 지정해야 되지만 <Type> 형태의 단어를 사용했다.
그럼에도 타입스크립트 제네릭을 사용하는데 문제는 없다.
class Box<Type> {
value: Type;
constructor(value: Type) {
this.value = value;
}
}타입스크립트 제네릭에서 <T>의 T라는 단어는
T, Type, Item처럼 의미에 맞는 이름을 사용할 수 있다.
클래스의 static 멤버에서 클래스 타입 매개변수를 직접 사용할 수 없다.
다음 코드는 허용되지 않는다.
class Box<T> {
static defaultValue: T;
}제네릭 클래스의 클래스 타입 매개변수 자체는 인스턴스이며,
정적 멤버는 해당 클래스 타입 매개변수를 참조할 수 없다.
난해하다면, 단순히 아래의 코드 형태를 눈으로 익혀두도록 한다.
class Box<T> {
constructor(public value: T) {}
}
const a = new Box<number>(100);
const b = new Box<string>("Hello");![]() |
| 제네릭 클래스 주의할 점 |








댓글
댓글 쓰기