TypeScript 제네릭(Generic)의 모든 것 – 재사용 가능한 타입 만들기 (16강)
**TypeScript 제네릭(Generic)**은 타입을 **동적으로** 정의할 수 있는 매우 유용한 기능으로, 코드의 재사용성과 타입 안전성을 동시에 높일 수 있습니다. 제네릭을 활용하면 **타입을 매개변수화**하여 다양한 데이터 타입을 처리할 수 있는 함수나 클래스를 만들 수 있습니다. 이번 강의에서는 **TypeScript 제네릭**의 개념과 사용법을 자세히 설명하고, 제네릭을 활용하여 **재사용 가능한 타입**을 어떻게 만들 수 있는지 알아보겠습니다.
제네릭(Generic) 개념 이해하기
**제네릭(Generic)**은 **타입 매개변수**를 사용하여 타입을 **유연하게 다룰 수 있는** 기능입니다. 제네릭을 사용하면 특정 데이터 타입에 구애받지 않고 **함수**나 **클래스**를 정의할 수 있어, 다양한 타입에 대해 **재사용 가능한 코드**를 작성할 수 있습니다.
예를 들어, 함수의 매개변수와 반환값이 어떤 타입인지 명확히 알 수 없을 때, 제네릭을 사용하면 이를 **동적으로 정의**할 수 있습니다. 이렇게 함으로써 코드의 **유연성**과 **타입 안정성**을 높일 수 있습니다.
TypeScript 제네릭 기본 문법
TypeScript에서 제네릭을 사용하는 기본 문법은 다음과 같습니다. 제네릭은 **
1. 제네릭 함수 예제
가장 기본적인 제네릭 함수의 예제를 살펴보겠습니다. 제네릭 함수는 다양한 데이터 타입을 처리할 수 있도록 **타입을 매개변수화**하여 정의할 수 있습니다.
function identity(arg: T): T {
return arg;
}
let result1 = identity(42); // number 타입
let result2 = identity("Hello, world!"); // string 타입
위 예제에서 **identity** 함수는 제네릭 함수로, **T**는 함수의 **입력 타입**과 **출력 타입**을 모두 매개변수화합니다. `identity(42)`를 호출하면 **number** 타입이 **T**에 할당되고, `identity("Hello, world!")`를 호출하면 **string** 타입이 **T**에 할당됩니다.
2. 제네릭 배열 함수
제네릭을 사용하여 배열의 타입도 동적으로 정의할 수 있습니다. 예를 들어, 배열의 각 요소가 모두 같은 타입임을 보장하는 함수는 다음과 같이 작성할 수 있습니다.
function printArray(arr: T[]): void {
arr.forEach((item) => console.log(item));
}
printArray([1, 2, 3]); // number 배열
printArray(["apple", "banana", "cherry"]); // string 배열
**printArray** 함수는 제네릭을 사용하여 배열의 타입을 **동적으로 지정**합니다. 이 함수는 **number 배열**과 **string 배열**을 모두 처리할 수 있습니다. 제네릭을 통해 배열의 요소 타입을 확정할 수 있습니다.
제네릭 인터페이스와 클래스
제네릭을 함수 외에도 **인터페이스**와 **클래스**에서 사용할 수 있습니다. 제네릭을 클래스나 인터페이스에 적용하면, 다양한 타입을 처리하는 **재사용 가능한** 클래스를 작성할 수 있습니다.
1. 제네릭 인터페이스
제네릭 인터페이스를 사용하면 **다양한 타입의 객체**를 처리하는 인터페이스를 정의할 수 있습니다. 예를 들어, **데이터베이스**에서 정보를 다루는 인터페이스를 제네릭으로 작성할 수 있습니다.
interface Box {
value: T;
}
let numberBox: Box = { value: 42 };
let stringBox: Box = { value: "Hello" };
위 예제에서 **Box** 인터페이스는 **value** 속성의 타입을 **T**로 지정하여, 다양한 타입의 값을 **box** 객체로 감쌀 수 있습니다. 이를 통해 같은 인터페이스를 사용하면서도 다른 타입을 처리할 수 있습니다.
2. 제네릭 클래스
**제네릭 클래스**는 객체의 속성이나 메서드가 다양한 타입을 처리할 수 있도록 합니다. 제네릭을 사용하여 **재사용 가능한 클래스**를 쉽게 만들 수 있습니다.
class Container {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
getItems(): T[] {
return this.items;
}
}
let numberContainer = new Container();
numberContainer.add(1);
numberContainer.add(2);
console.log(numberContainer.getItems()); // [1, 2]
let stringContainer = new Container();
stringContainer.add("apple");
stringContainer.add("banana");
console.log(stringContainer.getItems()); // ["apple", "banana"]
위 예제에서 **Container** 클래스는 제네릭을 사용하여 다양한 타입의 **배열**을 저장할 수 있는 클래스를 정의합니다. `numberContainer`와 `stringContainer`를 생성하면서, 각각 **number** 타입과 **string** 타입의 데이터를 처리할 수 있습니다.
제네릭을 활용한 고급 기능
제네릭을 활용하여 좀 더 고급 기능을 구현할 수도 있습니다. 예를 들어, 제네릭을 **제약 조건**(constraints)을 설정하여 특정 타입만 허용하도록 만들 수 있습니다.
1. 제네릭 제약 조건
**제네릭 제약 조건**을 사용하면 특정 **타입**만 제네릭으로 사용할 수 있도록 제한할 수 있습니다. 예를 들어, 객체가 특정 속성을 갖는 경우에만 제네릭 타입을 사용할 수 있습니다.
interface Lengthwise {
length: number;
}
function logLength(item: T): void {
console.log(item.length);
}
logLength("Hello, world!"); // 13
logLength([1, 2, 3, 4]); // 4
위 예제에서 **T extends Lengthwise**는 **T**가 **length** 속성을 가진 객체에만 적용되도록 제약을 걸어줍니다. 이를 통해 **배열**이나 **문자열**처럼 **length** 속성을 가진 타입만 **logLength** 함수에서 사용될 수 있습니다.
2. 여러 제네릭 매개변수
**여러 제네릭 매개변수**를 사용하여 함수나 클래스에서 복잡한 타입을 처리할 수 있습니다. 예를 들어, 두 가지 이상의 타입을 다루는 함수나 클래스를 만들 수 있습니다.
function pair(first: T, second: U): [T, U] {
return [first, second];
}
let result = pair("hello", 42); // [string, number]
console.log(result);
**pair** 함수는 **T**와 **U**라는 두 가지 타입을 받아 **튜플**로 반환합니다. 이를 통해 다양한 **복합적인 타입**을 처리할 수 있습니다.
제네릭을 활용한 TypeScript 코드의 장점
**제네릭(Generic)**을 활용하면 코드의 **재사용성**과 **타입 안정성**을 높일 수 있습니다. 제네릭을 통해 타입을 동적으로 다루면서도 컴파일 시점에 타입 검사를 강화할 수 있기 때문에, 버그를 사전에 예방할 수 있습니다.
- 타입 안전성: 제네릭은 코드에서 잘못된 타입 사용을 방지하여 타입 안정성을 높입니다.
- 유연성: 제네릭을 사용하면 다양한 타입을 처리할 수 있어 코드의 유연성이 향상됩니다.
- 재사용성: 제네릭을 활용한 함수나 클래스는 다양한 데이터 타입에 대해 재사용이 가능하여 코드의 유지보수성이 높아집니다.
결론
**TypeScript 제네릭(Generic)**은 **타입을 매개변수화**하여 다양한 데이터 타입을 안전하고 유연하게 처리할 수 있는 기능입니다. 제네릭을 활용하면 **재사용 가능한 코드**를 작성할 수 있으며, 코드의 **유연성**과 **타입 안정성**을 모두 보장할 수 있습니다. 이번 강의를 통해 제네릭의 기본 개념과 고급 기능을 이해하고, 실제 코드에 적용해 보시기 바랍니다.