제너릭은 타입을 변수처럼 사용할 수 있도록 해주는 TypeScript의 기능입니다. 이를 통해 함수, 클래스, 인터페이스 등에서 다양한 타입을 유연하게 처리할 수 있습니다.
function identity<T>(arg: T): T {
return arg;
}
console.log(identity<string>("Hello")); // "Hello"
console.log(identity<number>(42)); // 42
✔️ T
는 타입 변수로 호출할 때 타입을 지정할 수 있습니다.
✔️ 함수 호출 시 타입을 명시적으로 지정하거나, 타입 추론이 가능합니다.
interface KeyValuePair<K, V> {
key: K;
value: V;
}
const kv1: KeyValuePair<string, number> = { key: "age", value: 30 };
const kv2: KeyValuePair<number, boolean> = { key: 1, value: true };
✔️ K
와 V
는 호출 시 타입을 동적으로 지정할 수 있습니다.
class DataStorage<T> {
private data: T[] = [];
addItem(item: T) {
this.data.push(item);
}
getItems(): T[] {
return this.data;
}
const textStorage = new DataStorage<string>();
textStorage.addItem("Apple");
console.log(textStorage.getItems()); // ["Apple"]
}
✔️ 제너릭을 활용해 다양한 타입의 데이터 저장소를 만들 수 있습니다.
function logLength<T extends { length: number }>(arg: T): number {
return arg.length
}
console.log(logLength("Hello")); // 5
console.log(logLength([1, 2, 3])); // 3
✔️ T extends { length: number }
를 사용하여 특정 속성ㅇ르 가진 타입만 허용할 수 있습니다.
keyof
와 함께 사용하기function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const person = { name: "Alice", age: 25 };
console.log(getProperty(person, "name")); // "Alice"
✔️ K extends keyof T
를 활용하면 객체의 키를 제한할 수 있습니다.
function createArray<T = string>(length: number, value: T): T[] {
return new Array(length).fill(value)
}
✔️ <T = string>
을 통해 기본 타입을 지정할 수 있습니다.
extends
키워드에 대한 자세한 설명extends
키워드는 제너릭 타입에 특정 제약을 걸고 싶을 때 사용합니다.
extends
사용법function printName<T extends { name: string }>(obj: T){
console.log(obj.name);
}
printName({ name: "Alice" }); // ✅ 정상
printName({ name: "Bob", age: 25 }); // ✅ 정상
//printName({ age: 30 }); // ❌ 오류: name 속성이 없음
✔️ T extends { name: string }
는 반드시 name
속성이 포함된 객체만 허용합니다.
function addNumber<T extends number>(a: T, b: T): number {
return a + b;
}
console.log(addNumbers(5, 10)); // ✅ 정상
// console.log(addNumbers("5", "10")); // // ❌ 오류: 숫자가 아님
✔️ T extends number
를 사용하면 숫자 타입만 받을 수 있도록 제한할 수 있습니다.
extends
활용하기class Animal {
constructor(public name: string) {}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
function makeNoise<T extends Animal>(animal: T) {
console.log(`${animal.name} is making a noise`);
}
const dog = new Dog("Buddy");
makeNoise(dog); // ✅ 정상
// makeNoise({ name: "Charlie" }); // ❌ 오류: Animal 클래스를 확장하지 않음
✔️ T extends Animal
을 사용하여 Animal 클래스를 확장한 객체만 허용할 수 있습니다.
function add<T>(a: T, b: T): T {
return a + b; // ❌ 오류 발생
}
❗ 제너릭은 타입이 정확히 정의되지 않으므로, 연산을 수행할 수 없습니다.
✔️ 해결 방법: extends
를 사용해 숫자 타입으로 제한해야 합니다.
❗ 너무 많은 제너릭을 사용하면 가독성이 떨어질 수 있습니다.
✔️ 단순한 경우에는 제너릭 없이 명확한 타입을 사용하는 것이 더 좋을 수 있습니다.