타입을 미리 고정하지 않고, 사용하는 시점에 결정하는 제네릭의 기본부터 제약 조건까지 정리합니다.
1. 제네릭이 필요한 이유
동일한 함수를 다양한 타입의 배열에 사용하고 싶다고 가정해봅시다.
// number 배열, string 배열 모두 길이를 구하고 싶다면?
// → 함수 오버로드? 유니온 타입?
// → 타입이 계속 늘어나면 그때마다 추가해야 한다
오버로드나 유니온으로도 해결할 수 있지만, 타입이 늘어날 때마다 코드를 수정해야 합니다. 제네릭을 사용하면 선언 시에는 타입을 비워두고, 호출 시에 타입을 결정할 수 있습니다.
2. 제네릭 함수
<T>를 타입 파라미터라고 합니다. 함수를 호출할 때 전달하는 타입에 따라 T가 결정됩니다.
function getSize<T>(arr: T[]): number {
return arr.length;
}
const arr1 = [1, 2, 3];
getSize<number>(arr1); // 3 — T가 number로 결정
const arr2 = ['1', '2', '3'];
getSize(arr2); // 3 — T가 string으로 자동 추론
💡 <number>처럼 타입을 직접 기입할 수도 있고, 생략하면 전달된 매개변수를 보고 TypeScript가 자동으로 추론합니다. 특정 타입을 명확히 강조하고 싶을 때만 직접 기입하면 됩니다.
3. 제네릭 인터페이스
인터페이스에서도 제네릭을 사용할 수 있습니다. 특정 프로퍼티의 타입이 상황에 따라 달라질 때 유용합니다.
interface Mobile<T> {
name: string;
price: number;
option: T; // 어떤 타입이든 올 수 있음
}
사용 예시
// option이 객체인 경우
const m1: Mobile<object> = {
name: "s21",
price: 1000,
option: {
color: "red",
coupon: false,
}
}
// option이 문자열인 경우
const m2: Mobile<string> = {
name: "s21",
price: 1000,
option: "red"
}
객체 구조가 정해져 있다면 Mobile<{ color: string; coupon: boolean }>처럼 구체적으로 지정할 수도 있습니다.
4. 제네릭 제약 조건 (extends)
제네릭은 어떤 타입이든 받을 수 있다는 장점이 있지만, 그래서 특정 프로퍼티가 있다고 보장할 수 없는 문제가 생깁니다.
문제 상황
interface User {
name: string;
age: number;
}
interface Car {
name: string;
color: string;
}
interface Book {
price: number;
}
function showName<T>(data: T): string {
return data.name; // ❌ Error — T에 name 속성이 있다고 보장할 수 없음
}
User나 Car에는 name이 있지만, 제네릭 T는 어떤 타입이든 될 수 있으므로 TypeScript는 name에 접근하는 것을 허용하지 않습니다.
extends로 해결
T extends { name: string }을 사용하면 "T는 최소한 name: string을 가진 타입이다"라는 제약을 걸 수 있습니다.
function showName<T extends { name: string }>(data: T): string {
return data.name; // ✅ OK — name이 있다고 보장됨
}
const user: User = { name: "a", age: 10 };
const car: Car = { name: "bmw", color: "red" };
const book: Book = { price: 3000 };
showName(user); // ✅ OK — name 있음
showName(car); // ✅ OK — name 있음
showName(book); // ❌ Error — Book에는 name이 없음
💡 extends는 "이 타입을 확장한 것만 허용한다"는 의미입니다. 제네릭의 유연함을 유지하면서도, 필요한 프로퍼티가 반드시 존재하도록 안전하게 제한할 수 있습니다.
한눈에 보기
기능 문법 설명
| 제네릭 함수 | function fn<T>(arg: T) | 호출 시 타입 결정 |
| 타입 명시 호출 | fn<number>(arg) | 타입을 직접 지정 |
| 타입 추론 호출 | fn(arg) | 매개변수로 자동 추론 |
| 제네릭 인터페이스 | interface Mobile<T> | 프로퍼티 타입을 유동적으로 |
| 제약 조건 | T extends { name: string } | T가 가져야 할 최소 조건 |
'프론트' 카테고리의 다른 글
| TypeScript 유틸리티 타입(Utility Types) (1) | 2026.04.11 |
|---|---|
| TypeScript 클래스(Class) (0) | 2026.04.11 |
| TypeScript 리터럴 · 유니온 · 교차 타입 정리 (0) | 2026.04.11 |
| TypeScript 함수 타입 (0) | 2026.04.11 |
| TypeScript 인터페이스(Interface) (0) | 2026.04.11 |