타입스크립트의 제네릭
이 기사에서는 타입스크립트에서 제네릭에 대해 설명합니다.
YouTube Video
타입스크립트의 제네릭
타입스크립트의 제네릭은 타입을 매개변수화하여 재사용 가능하고 타입 안전한 함수, 클래스, 인터페이스를 정의할 수 있는 기능입니다. 제네릭을 사용하면 특정 타입에 의존하지 않는 코드를 작성할 수 있으므로 다양한 타입에서 동일한 작업을 수행할 수 있습니다.
제네릭의 기초
제네릭은 타입을 인수로 취하는 템플릿처럼 작동하여 함수와 클래스가 다양한 타입을 다룰 수 있도록 합니다.
제네릭 함수
다음은 제네릭을 사용하여 인수 타입을 지정한 함수의 예입니다.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity<number>(42)); // 42
6console.log(identity<string>("Hello")); // Hello
T
는 함수 인수 및 반환 값의 타입을 나타내는 제네릭 타입 인수입니다. 실제 타입은 함수가 호출될 때 결정됩니다.<number>
또는<string>
을 명시적으로 지정하여 타입을 정의하는 것입니다.
타입스크립트는 타입 추론을 수행하므로 제네릭 타입은 명시적 지정 없이도 작동합니다.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity(42)); // 42
6console.log(identity("Hello")); // Hello
제네릭의 제한 조건
제네릭에 제한 조건을 두면 특정 타입만 허용하도록 제한할 수 있습니다.
1function loggingIdentity<T extends { length: number }>(arg: T): T {
2 console.log(arg.length);
3 return arg;
4}
5
6loggingIdentity("Hello"); // 5
7loggingIdentity([1, 2, 3]); // 3
8
9// loggingIdentity(42); // Error: number does not have a length property.
T extends { length: number }
를 지정하면T
는 반드시length
속성을 가진 타입이어야 함을 의미합니다. 따라서length
속성이 없는 타입은 허용되지 않습니다.
제네릭 클래스
클래스도 제네릭을 사용하여 정의할 수 있습니다. 제네릭 클래스는 프로퍼티와 메서드에 유연한 타입을 제공합니다.
1class Box<T> {
2 private _value: T;
3
4 constructor(value: T) {
5 this._value = value;
6 }
7
8 public getValue(): T {
9 return this._value;
10 }
11
12 public setValue(value: T): void {
13 this._value = value;
14 }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue()); // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue()); // Hello
Box<T>
는 클래스 내에서 사용되는 타입T
를 제네릭으로 선언합니다. 이를 통해 동일한 클래스를 다양한 타입에 재사용할 수 있습니다.
제네릭 인터페이스
제네릭은 인터페이스에서도 사용할 수 있습니다.
1interface Pair<T, U> {
2 first: T;
3 second: U;
4}
5
6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
7console.log(numberStringPair); // { first: 1, second: 'One' }
8
9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair); // { first: true, second: [ 1, 2, 3 ] }
Pair<T, U>
로 두 가지 제네릭 타입을 지정하면 서로 다른 타입의 조합으로 객체를 정의할 수 있습니다.
기본 타입 인수
제네릭 타입 인수에 대해 기본 타입을 지정하는 것도 가능합니다.
1function createArray<T = string>(length: number, value: T): T[] {
2 return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a")); // ['a', 'a', 'a']
6console.log(createArray(3, 100)); // [100, 100, 100]
<T = string>
을 사용해 기본 타입 인수를string
으로 설정하고 있습니다. 명시적으로 타입을 지정하지 않으면T
는string
타입이 됩니다.
제네릭 타입 별칭
제네릭은 타입 별칭(type
)으로도 사용할 수 있습니다.
1type Result<T> = {
2 success: boolean;
3 data: T;
4};
5
6const successResult: Result<number> = { success: true, data: 42 };
7const errorResult: Result<string> = { success: false, data: "Error occurred" };
8
9console.log(successResult); // { success: true, data: 42 }
10console.log(errorResult); // { success: false, data: 'Error occurred' }
Result<T>
는T
타입의 데이터를 포함하는 결과 객체를 나타냅니다. 이와 같은 방식으로, 제네릭을 사용하여 유연한 타입 별칭을 만들 수 있습니다.
다중 제네릭 타입
다중 제네릭 타입을 사용하면, 더욱 다양한 기능을 가진 함수와 클래스를 정의할 수 있습니다.
1function merge<T, U>(obj1: T, obj2: U): T & U {
2 return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged); // { name: 'Alice', title: 'Engineer' }
merge
함수는 두 가지 다른 타입T
와U
를 받아 이를 결합하여 새로운 객체를 반환합니다.
요약
- 제네릭은 타입을 매개변수로 처리하여 재사용 가능하고 타입 안전한 코드를 작성할 수 있도록 해줍니다.
- 함수, 클래스, 인터페이스에서 제네릭을 사용하면 다양한 타입을 다룰 수 있는 유연한 로직을 작성할 수 있습니다.
- 타입 인수에 제약을 추가하거나 기본 타입 인수를 설정하여 제네릭의 범위를 제어할 수 있습니다.
제네릭을 사용함으로써 타입에 의존하지 않는 범용 코드를 작성할 수 있으며, TypeScript의 강력한 타입 시스템을 최대한 활용할 수 있습니다.
위의 기사를 보면서 Visual Studio Code를 사용해 우리 유튜브 채널에서 함께 따라할 수 있습니다. 유튜브 채널도 확인해 주세요.