개발
TypeScript 제네릭 완벽 가이드: 타입 안정성 높이기
TypeScript 제네릭의 개념부터 실전 활용까지. 타입 안정성을 유지하면서 재사용 가능한 코드를 작성하는 방법을 예제 중심으로 배워봅니다.
TypeScript
제네릭
타입스크립트
웹개발
프론트엔드
제네릭이란?
제네릭은 타입을 파라미터처럼 전달할 수 있게 하는 TypeScript 기능입니다. any 타입에 의존하지 않고도 유연하고 재사용 가능한 코드를 작성할 수 있습니다.
기본 문법
제네릭 없이
function getFirst(arr: number[]): number {
return arr[0];
}
// 문자열 배열에는 사용 불가 ❌
제네릭 사용
function getFirst<T>(arr: T[]): T {
return arr[0];
}
const num = getFirst([1, 2, 3]); // number
const str = getFirst(['a', 'b']); // string
실전 패턴 1: API 응답 타입
interface ApiResponse<T> {
success: boolean;
data: T;
message: string;
}
interface User {
id: number;
name: string;
}
async function fetchUser(id: number): Promise<ApiResponse<User>> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// 타입 안정성 확보 ✅
const result = await fetchUser(1);
console.log(result.data.name); // User 타입으로 자동 추론
실전 패턴 2: 유틸리티 함수
function pluck<T, K extends keyof T>(arr: T[], key: K): T[K][] {
return arr.map(item => item[key]);
}
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
];
const names = pluck(users, 'name'); // string[]
const ages = pluck(users, 'age'); // number[]
// 존재하지 않는 키는 에러 ❌
const invalid = pluck(users, 'salary'); // 컴파일 에러!
실전 패턴 3: React 컴포넌트
interface TableProps<T> {
data: T[];
columns: {
key: keyof T;
header: string;
}[];
}
function Table<T>({ data, columns }: TableProps<T>) {
return (
<table>
<thead>
<tr>
{columns.map(col => (
<th key={String(col.key)}>{col.header}</th>
))}
</tr>
</thead>
<tbody>
{data.map((item, idx) => (
<tr key={idx}>
{columns.map(col => (
<td key={String(col.key)}>
{String(item[col.key])}
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
고급 패턴: 조건부 타입
type Unwrap<T> = T extends Promise<infer U> ? U : T;
type A = Unwrap<Promise<string>>; // string
type B = Unwrap<number>; // number
흔한 실수
❌ 제네릭 제약 조건 누락
// 나쁜 예
function getProp<T>(obj: T, key: string) {
return obj[key]; // 에러!
}
// 좋은 예
function getProp<T, K extends keyof T>(obj: T, key: K) {
return obj[key]; // 타입 안전 ✅
}
❌ 과도한 제네릭 사용
// 나쁜 예 (불필요하게 복잡)
function add<T extends number>(a: T, b: T): T {
return (a + b) as T;
}
// 좋은 예 (단순)
function add(a: number, b: number): number {
return a + b;
}
핵심 정리
제네릭은 타입 안정성과 코드 재사용성을 모두 제공합니다. API 응답 타입 정의, 공통 유틸리티 함수, React 컴포넌트 등에서 적극 활용하면 런타임 에러를 줄이고 생산성을 높일 수 있습니다.