네, 9강에 오신 것을 진심으로 환영합니다! 🎉 많은 분들이 타입스크립트를 공부하다가 "아, 제네릭(Generic)이 도대체 뭐야... <T> 이거 나오니까 머리가 핑 도네" 하고 책을 덮는 구간입니다.
하지만 걱정 마세요. 저와 함께라면 아주 쉽게 넘을 수 있습니다. 제네릭은 사실 우리가 이미 알고 있는 **'함수 파라미터'**와 똑같은 원리거든요.
🚀 제9강. 만능 열쇠, 제네릭(Generics) 기초: "타입도 변수처럼 넘겨주자"
1. 왜 필요한가요? (문제점 인식)
우리가 어떤 데이터를 받아서 그대로 다시 뱉어주는 아주 단순한 함수를 만든다고 가정해 봅시다.
// 숫자 전용 함수: 숫자를 잘 처리하지만 문자는 못 받음
function echoNumber(message: number): number {
return message;
}
// 문자 전용 함수: 문자는 잘 처리하지만 숫자는 못 받음
function echoString(message: string): string {
return message;
}
데이터 타입 하나 바뀐다고 똑같은 로직의 함수를 계속 새로 만들어야 할까요? 너무 비효율적이죠. 그렇다고 **any**를 쓰자니 타입 체크를 포기하는 꼴이 됩니다.
이때 필요한 게 바로 제네릭입니다. "타입을 미리 정하지 말고, 함수를 쓸 때 그때그때 정해서 알려줄게!" 하는 방식입니다.
2. 개념 쏙쏙: "테이크아웃 컵" 비유 🥤
💡 비유: 카페의 투명한 테이크아웃 컵을 생각해 보세요.
- 공장에서 컵을 만들 때는 내용물을 정하지 않습니다. 그냥 **'담을 수 있는 용기'**만 만듭니다.
- 손님이 주문할 때 비로소 결정됩니다.
- 커피를 담으면 -> 커피 컵이 되고,
- 오렌지 주스를 담으면 -> 주스 컵이 됩니다.
제네릭이 바로 이 **'빈 컵'**입니다.
3. 문법 뽀개기 (<T>)
자, 이제 그 무섭다는 꺽쇠 괄호 < >를 정복해 봅시다.
- () 괄호 안에는 **값(데이터)**을 변수로 받죠?
- < > 괄호 안에는 타입을 변수로 받습니다. 보통 Type의 약자인 **T**를 많이 씁니다.
// 1. 함수 이름 뒤에 <T>를 붙여서 "이 함수는 제네릭(빈 컵)이야"라고 선언합니다.
// 2. 매개변수의 타입과 반환 타입 자리에 T를 적습니다.
function echo<T>(message: T): T {
return message;
}
// 사용법 1: "나 지금 <string> 담을 거야!"라고 명시하기
const result1 = echo<string>("안녕하세요");
// 이제 result1은 string 타입이 됩니다.
// 사용법 2: "나 지금 <number> 담을 거야!"
const result2 = echo<number>(123);
// 이제 result2는 number 타입이 됩니다.
보세요! 함수 하나(echo)로 문자열도 처리하고 숫자도 처리했죠? 그런데도 any와 달리 타입은 정확하게 지켜집니다.
- result1에 숫자를 넣으려 하거나, result1.toFixed()(숫자 함수)를 쓰면 에러가 납니다. 왜냐? <string>으로 주문했으니까요!
4. 타입스크립트의 센스 (타입 추론)
사실 실무에서는 <number>, <string> 이렇게 매번 적지 않아도 됩니다. 타입스크립트가 똑똑해서 "어? 들어가는 값이 숫자(100)네? 그럼 T는 number겠구나!" 하고 알아서 눈치챕니다.
// <number>를 생략해도 됩니다.
const result3 = echo(100); // TS: "음, T는 number군."
// <string>을 생략해도 됩니다.
const result4 = echo("반갑다"); // TS: "음, T는 string이군."
그래서 코드가 아주 깔끔해집니다.
✍️ 9강 미니 퀴즈 & 실습
제네릭, 생각보다 별거 아니죠? 그냥 **'타입을 위한 변수'**입니다.
문제 1. (개념 확인) 다음 중 제네릭을 사용하는 이유로 가장 적절한 것은?
- 타입 체크를 아예 하지 않기 위해 (any처럼 쓰려고)
- 하나의 코드로 여러 타입을 안전하게 처리하기 위해 (코드 재사용성)
- 함수의 실행 속도를 빠르게 하기 위해
문제 2. (코드 완성) 배열을 받아서 배열의 길이를 반환하는 것이 아니라, 배열의 첫 번째 요소를 반환하는 제네릭 함수 getFirst를 만들고 싶습니다. 빈칸을 채워보세요.
function getFirst<T>(arr: T[]): ( A ) {
return arr[0];
}
const num = getFirst<number>([1, 2, 3]); // 1이 나옴
const str = getFirst<string>(["a", "b", "c"]); // "a"가 나옴
**(A)**에 들어갈 코드는 무엇일까요?
- any
- number
- T
✅ 정답 및 해설
- 문제 1 정답: 2번
- 해설: 제네릭의 핵심은 재사용성과 안전성 두 마리 토끼를 다 잡는 것입니다. any를 쓰면 안전성을 잃지만, 제네릭은 타입을 지켜줍니다.
- 문제 2 정답: 3번 (T)
- 해설:
- arr: T[]: T 타입의 요소들이 들어있는 배열을 받았습니다. (예: 숫자 배열)
- return arr[0]: 그중 하나를 꺼내면 당연히 그 타입은 T겠죠? (예: 숫자)
- 그래서 반환 타입(출구)도 T가 되어야 합니다.
- 해설:
고생하셨습니다! 👏 이제 여러분은 <T>를 보고도 겁먹지 않는 수준이 되었습니다. "아, 저 자리에 내가 원하는 타입을 끼워 넣으면 되는구나!"라고 생각하시면 됩니다.
하지만 제네릭이 진짜 빛을 발하는 순간은 API 통신을 할 때입니다. 서버에서 어떤 데이터가 올지 모를 때 제네릭이 구세주가 되어줍니다.
다음 10강에서는 이 제네릭을 실제 인터페이스와 함수에 활용하는 실전 테크닉을 배워보겠습니다. Part 2의 마지막 관문입니다!
'개발 > Typescript' 카테고리의 다른 글
| Typescript 완벽 가이드|기초부터 실전까지 한 번에 정리 - 10강 (0) | 2026.01.21 |
|---|---|
| Typescript 완벽 가이드|기초부터 실전까지 한 번에 정리 - 8강 (1) | 2026.01.21 |
| Typescript 완벽 가이드|기초부터 실전까지 한 번에 정리 - 7강 (0) | 2026.01.21 |
| Typescript 완벽 가이드|기초부터 실전까지 한 번에 정리 - 6강 (1) | 2026.01.21 |
| Typescript 완벽 가이드|기초부터 실전까지 한 번에 정리 - 5강 (0) | 2026.01.21 |