1️⃣ 타입 변수 선언 (Generic Type Parameters)
- 함수나 클래스에서 타입을 변수처럼 받아 다양한 타입에 유연하게 대응할 수 있다.
- 타입 변수는 보통
T, U, V 등의 대문자 한 글자로 표현한다.
- 여러 개의 타입 변수를 사용할 수 있으며, 각 타입은 호출 시점에 추론되거나 명시적으로 지정할 수 있다.
function swap<T, U>(a: T, b: U): [U, T] {
return [b, a];
}
const [a, b] = swap("1", 2);
2️⃣ 배열과 튜플 타입
- 제네릭 함수에서 고정된 첫 요소 타입과 가변적인 나머지 요소 타입을 표현할 수 있다.
- 이럴 때는 튜플 타입과
...rest 패턴을 사용하면 유용하다.
function returnFirstValue<T>(data: [T, ...unknown[]]): T {
return data[0];
}
const num = returnFirstValue([0, 1, 2]);
const str = returnFirstValue(["hello", "world"]);
const mixed = returnFirstValue([1, "hello", true]);
- ✅
unknown[]은 나머지 요소들의 타입이 무엇이든 상관없음을 명시할 때 유용
3️⃣ extends 키워드로 타입 제약 걸기
- 제네릭 타입 변수에 특정 조건(제약)을 걸고 싶을 때
extends를 사용한다.
- 예:
length 속성이 존재해야 하는 타입만 받게 제한할 수 있다.
function getLength<T extends { length: number }>(data: T): number {
return data.length;
}
getLength([1, 2, 3]);
getLength("12345");
getLength({ length: 10 });
getLength(10);
- ✅ 객체 리터럴, 배열, 문자열처럼
length 속성을 가진 타입만 허용
4️⃣ map, forEach 메서드를 직접 정의해보기
📍 제네릭 map 함수
- 입력 배열과 콜백 함수에 대해 각 요소를 변환한 새로운 배열을 반환
- 콜백 함수는
(item: T) => U 형태로, 입력과 출력 타입을 모두 명시
function map<T, U>(arr: T[], callback: (item: T) => U): U[] {
const result: U[] = [];
for (let i = 0; i < arr.length; i++) {
result.push(callback(arr[i]));
}
return result;
}
map([1, 2, 3], (it) => it * 2);
map(["1", "2"], (it) => parseInt(it));
map(["hi", "hello"], (it) => it.toUpperCase());
📍 제네릭 forEach 함수
- 각 요소에 대해 콜백 함수만 실행하고 결과는 반환하지 않는다.
- 콜백 함수의 반환 타입은
void
function forEach<T>(arr: T[], callback: (item: T) => void): void {
for (let i = 0; i < arr.length; i++) {
callback(arr[i]);
}
}
forEach([1, 2, 3], (it) => {
console.log(it.toFixed());
});
forEach(["123", "456"], (it) => {
console.log(parseInt(it));
});
- ✅
forEach는 부수 효과(side-effect)를 위한 용도로 사용됨