타입스크립트 제네릭은 다양한 데이터 유형을 처리할 수 있는 유연한 함수, 클래스, 인터페이스를 만드는 방법입니다. 제네릭을 사용하면 코드를 더욱 재사용 가능하고 유지 보수하기 쉽게 만들 수 있습니다.
제네릭 함수
제네릭 함수는 다양한 유형의 인수를 받아서 동일한 작업을 수행하는 함수입니다. 제네릭 함수를 사용하면 코드를 더욱 유연하고 재사용 가능하게 만들 수 있습니다.
function identity<T>(value: T): T {
return value;
}
const result = identity<number>(10); // 10
const result2 = identity<string>("Hello"); // "Hello"
위의 예시에서 identity 함수는 어떤 유형의 값이든 받아서 그대로 반환합니다. 이 함수는 숫자, 문자열, 객체 등 어떤 유형의 값이든 사용할 수 있습니다.
제네릭 클래스
제네릭 클래스는 다양한 유형의 데이터를 저장할 수 있는 클래스입니다. 제네릭 클래스를 사용하면 코드를 더욱 유연하고 재사용 가능하게 만들 수 있습니다.
class Queue<T> {
private data: T[] = [];
enqueue(item: T) {
this.data.push(item);
}
dequeue() {
return this.data.shift();
}
}
const queue = new Queue<number>();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
console.log(queue.dequeue()); // 1
console.log(queue.dequeue()); // 2
console.log(queue.dequeue()); // 3
위의 예시에서 Queue 클래스는 어떤 유형의 데이터든 저장할 수 있는 큐를 구현합니다. 이 클래스는 숫자, 문자열, 객체 등 어떤 유형의 데이터든 사용할 수 있습니다.
제네릭 인터페이스
제네릭 인터페이스는 다양한 유형의 데이터를 처리할 수 있는 인터페이스입니다. 제네릭 인터페이스를 사용하면 코드를 더욱 유연하고 재사용 가능하게 만들 수 있습니다.
interface Comparable<T> {
compareTo(other: T): number;
}
class Number implements Comparable<number> {
constructor(public value: number) {}
compareTo(other: number) {
return this.value - other.value;
}
}
class String implements Comparable<string> {
constructor(public value: string) {}
compareTo(other: string) {
return this.value.localeCompare(other.value);
}
}
function sort(array: Comparable<T>[]): T[] {
return array.sort((a, b) => a.compareTo(b));
}
const numbers = [new Number(1), new Number(3), new Number(2)];
const strings = ["a", "c", "b"];
console.log(sort(numbers)); // [1, 2, 3]
console.log(sort(strings)); // ["a", "b", "c"]
위의 예시에서 Comparable 인터페이스는 compareTo 메서드를 정의합니다. Number 클래스와 String 클래스는 Comparable 인터페이스를 구현합니다. sort 함수는 Comparable 인터페이스를 구현한 배열을 정렬합니다.
제네릭 제약
제네릭 제약은 제네릭 함수, 클래스, 인터페이스에서 사용할 수 있는 유형을 제한합니다. 제네릭 제약을 사용하면 코드를 더욱 안전하고 예측 가능하게 만들 수 있습니다.
function identity<T extends number>(value: T): T {
return value;
}
const result = identity<number>(10); // 10
const result2 = identity<string>("Hello"); // 오류: string은 숫자가 아닙니다.
위의 예시에서 identity 함수는 숫자만 받을 수 있도록 제약되어 있습니다. 따라서 문자열을 전달하면 오류가 발생합니다.
분산
분산은 제네릭 유형이 어떻게 다른 유형과 관련되는지를 나타냅니다. 공변 분산은 자식 유형을 부모 유형으로 대체할 수 있음을 의미합니다. 반면, 반변 분산은 부모 유형을 자식 유형으로 대체할 수 있음을 의미합니다.
interface Box<T> {
item: T;
}
function box<T>(value: T): Box<T> {
return { item: value };
}
const boxOfNumber = box<number>(1);
const boxOfString = box<string>("Hello");
// 공변 분산
const boxOfAny: Box<any> = boxOfNumber;
boxOfAny.item = "Hello"; // 정상
// 반변 분산
const array: Array<number> = [1, 2, 3];
const boxedArray: Array<Box<number>> = array.map(box);
boxedArray[0].item = "Hello"; // 오류: string은 숫자가 아닙니다.
위의 예시에서 Box 클래스는 공변 분산입니다. 따라서 Box<number>를 Box<any>로 대체할 수 있습니다. 하지만 Array 클래스는 반변 분산입니다. 따라서 Array<number>를 Array<Box<number>>로 대체할 수 없습니다.
'Dev > TypeScript' 카테고리의 다른 글
TypeScript 모듈 시스템 심층 탐구: 해결 방식, 번들러 연동, 네임스페이스와의 차이, 최신 동향 (1) | 2024.12.16 |
---|---|
타입스크립트 템플릿 리터럴 타입: 더욱 정확한 타입 안전성을 위한 여정 (2) | 2024.12.13 |
TypeScript 모듈: 자세한 설명과 예시를 통한 가이드 (0) | 2024.12.04 |
TypeScript : Type Inference & Variable Declaration (3) | 2024.10.03 |
TypeScript : Type Compatibility (0) | 2024.10.02 |