제네릭 함수 활용 사례
사례 1: 여러 개의 타입 변수
두 값의 위치를 바꾸는 swap 함수를 만들어 보자.
function swap(a: any, b: any) {
return [b, a];
}
const [a, b] = swap(1, 2);
any타입을 사용하면 타입 안정성이 보장되지 않는다.
2개의 타입 변수가 필요한 상황이라면 다음과 같이 T, U 처럼 여러 개의 타입 변수를 사용할 수 있다.
function swap<T, U>(a: T, b: U) {
return [b, a];
}
const [a, b] = swap("1", 2);
위 코드에서 T는 string 타입으로, U는 number 타입으로 추론된다.
반환값은 [U, T] 즉, [number, string] 튜플 타입이 된다.

사례 2: 배열 요소 타입 추론
배열의 첫 번째 요소를 반환하는 함수를 만들어보자.
function returnFirstValue(data: any) {
return data[0];
}
let num = returnFirstValue([0, 1, 2]);
let str = returnFirstValue([1, "hello", "mynameis"]);
다양한 배열 타입을 인수로 받는 제네릭 함수는 다음과 같이 만들 수 있다.
function returnFirstValue<T>(data: T[]) {
return data[0];
}
let num = returnFirstValue([0, 1, 2]); // number
let str = returnFirstValue([1, "hello", "mynameis"]); // number | string
함수 매개변수 data의 타입을 T[]로 설정했기 때문에 배열이 아닌 값은 인수로 전달할 수 없으며, 배열을 인수로 전달하면 T는 배열의 요소 타입으로 추론된다.
첫 번째 호출에서는 number[] 타입의 값을 전달했으므로 T는 number 타입으로 추론되며, 반환값 타입도 number가 된다.
두 번째 호출에서는 (number | string)[] 타입의 값을 전달했으므로 T는 number | string 타입으로 추론되며, 반환값 타입도 number | string가 된다.

사례 3: 첫 번째 요소 타입만 추론
위 사례에서 반환값의 타입을 배열의 첫 번째 요소 타입으로 정확히 지정하려면 튜플 타입과 나머지 파라미터를 이용하면 된다.
function returnFirstValue<T>(data: [T, ...unknown[]]) {
return data[0];
}
let str = returnFirstValue([1, "hello", "mynameis"]); // number
함수 매개변수의 타입을 튜플 타입 [T, ...unknown[]]로 정의하면 첫 번째 요소의 타입은 T, 나머지 요소는 길이와 타입에 상관없이 받을 수 있다.
함수를 호출하고 [1, "hello", "mynameis"] 같은 배열을 인수로 전달하면 T는 첫 번째 요소의 타입인 number가 되며, 반환값 타입도 number가 된다.

사례 4: 타입 변수 제한하기
타입 변수를 제한한다는 것은 함수 호출 시 인수로 전달할 수 있는 값의 범위에 제한을 두는 것을 의미한다.
function getLength(data: any) {
return data.length;
}
let var1 = getLength([1, 2, 3]);
let var2 = getLength("12345");
let var3 = getLength({ length: 10 });
let var4 = getLength(10); // 런타임 오류
any 타입을 사용하면 length 프로퍼티가 없는 값도 전달할 수 있어 위험하다.
타입 변수를 length 프로퍼티를 갖는 타입으로 제한해보자.
function getLength<T extends { length: number }>(data: T) {
return data.length;
}
getLength("123"); // ✅
getLength([1, 2, 3]); // ✅
getLength({ length: 1 }); // ✅
getLength(10); // ❌
타입 변수를 제한할 때는 extends 키워드를 사용한다. T extends { length: number }로 정의하면 T는 { length: number } 객체 타입의 서브 타입이 된다.
즉, T는 무조건 number 타입의 length 프로퍼티를 가지고 있어야 한다. 따라서 문자열, 배열, length 프로퍼티를 가진 객체는 전달할 수 있지만, 숫자처럼 length가 없는 값은 전달할 수 없다.

'TIL' 카테고리의 다른 글
| [TS] 제네릭 인터페이스와 타입 별칭 (0) | 2025.11.04 |
|---|---|
| [TS] map, forEach 메서드 타입 정의하기 (0) | 2025.11.04 |
| [TS] 제네릭 (0) | 2025.11.04 |
| [CS50] 컴퓨팅 사고 - 2진법 (0) | 2025.11.03 |
| [TS] 클래스와 접근제어자 사용 연습 (0) | 2025.11.03 |
