TypeScript 심화 학습 완벽 가이드 | 제네릭부터 타입 유틸리티까지
TypeScript 기초에서 실무 레벨로 가는 길
JavaScript를 다루다가 TypeScript로 넘어가면, 처음엔 단순한 타입 체크로만 느껴집니다. 하지만 제네릭(Generic) 을 배우면 코드의 재사용성과 안전성이 극도로 높아집니다.
꼭 알아야 할 5가지 고급 개념
1. Generic (제네릭)
// 기본 제네릭
function getFirst<T>(arr: T[]): T {
return arr[0];
}
// 제약 조건
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// 실무 예: API 응답 래퍼
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
const userResponse: ApiResponse<User> = {
data: { id: 1, name: "Kim" },
status: 200,
message: "Success"
};2. Union & Intersection
// Union: 여러 타입 중 하나
type Status = "pending" | "success" | "error";
// Intersection: 여러 타입 결합
interface Name {
firstName: string;
lastName: string;
}
interface Age {
age: number;
}
type Person = Name & Age;
const person: Person = {
firstName: "Kim",
lastName: "Yido",
age: 30
};3. Mapped Types (타입 매핑)
// 모든 프로퍼티를 선택사항으로
type Optional<T> = {
[K in keyof T]?: T[K];
};
// 실무 예: React Props 타입
type UserInput = {
name: string;
email: string;
age: number;
};
type UserFormProps = Optional<UserInput>;
// 결과: { name?: string; email?: string; age?: number; }4. Conditional Types (조건부 타입)
// 타입에 따라 다른 타입 반환
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<123>; // false
// 실무 예: 액션 디스패치
type ExtractPayload<T> = T extends { payload: infer P } ? P : never;
type ActionType = {
type: 'UPDATE_USER';
payload: { id: number; name: string };
};
type Payload = ExtractPayload<ActionType>; // { id: number; name: string }5. Type Utilities (유틸리티 타입)
// Partial: 모든 프로퍼티 선택사항
type PartialUser = Partial<User>;
// Required: 모든 프로퍼티 필수
type RequiredUser = Required<User>;
// Readonly: 읽기 전용
type ReadonlyUser = Readonly<User>;
// Pick: 특정 프로퍼티만 선택
type UserPreview = Pick<User, 'id' | 'name'>;
// Omit: 특정 프로퍼티 제외
type UserWithoutPassword = Omit<User, 'password'>;
// Record: 키-값 맵핑
type UserRoles = Record<'admin' | 'user' | 'guest', User>;실무에서 자주 쓰는 패턴 10가지
1. API 응답 타입 정의
interface ApiRequest<T> {
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
endpoint: string;
data?: T;
}
async function fetchData<T>(request: ApiRequest<T>): Promise<T> {
// 구현...
}2. Redux 액션 타입
interface Action<T extends string, P = void> {
type: T;
payload?: P;
}
type UserActions =
| Action<'USER_FETCH', { id: number }>
| Action<'USER_UPDATE', User>
| Action<'USER_DELETE'>;3. 폼 입력 검증
type FormField<T> = {
value: T;
error?: string;
validate: (value: T) => boolean;
};
const emailField: FormField<string> = {
value: "test@example.com",
validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)
};학습 로드맵 (3개월)
1주차: 제네릭 기초
- 기본 제네릭 문법
- 타입 변수 이해
- 제약 조건 (extends)
2주차: Union/Intersection
- 유니온 타입
- 인터섹션 타입
- 타입 가드
3~4주차: 맵핑 & 조건부 타입
- Mapped Types
- Conditional Types
- 재귀적 타입
5~6주차: 실무 패턴
- Redux with TypeScript
- React Props 타입
- API 응답 타입
7~12주차: 프로젝트 구현
- 실무 프로젝트에 적용
- 라이브러리 타입 읽기
- 타입 안전성 검증
자주 묻는 질문 (FAQ)
TypeScript 제네릭이 왜 어려워요?
A. 제네릭은 "타입 함수"라고 생각하면 쉽습니다.function<T> = "어떤 타입이든 받아서 그 타입을 그대로 반환한다"는 의미입니다.any를 써도 되지 않을까요?
A. 절대 금지입니다.any를 쓰면 TypeScript의 장점이 모두 사라집니다. 모르는 타입은 unknown을 사용하세요.타입 선언이 너무 길어요
A. 이는 정상입니다. 대신 타입 재사용을 늘려야 합니다. 공통 타입은types.ts 파일에 별도로 정의하세요.실무에서 제네릭을 얼마나 쓰나요?
A. 제네릭을 안 쓰고 작업하기는 불가능합니다. API 응답, Redux 액션, 컴포넌트 Props 모두 제네릭이 필수입니다.TypeScript 성능이 느려지지 않나요?
A. 타입 검사는 컴파일 타임에 일어나므로, 런타임 성능에 영향이 없습니다. 오히려 버그를 줄여 전체 성능을 높입니다.추천 학습 자료
마치며
TypeScript 심화는 개발 속도와 코드 품질을 동시에 높입니다. 처음엔 복잡해 보이지만, 한 번 익숙해지면 JavaScript로는 돌아갈 수 없습니다!
관련 글:
핵심 체크리스트
- [ ] 이 글의 핵심 내용을 이해했는가?
- [ ] 나의 상황에 적용할 수 있는 부분은?
- [ ] 추가로 확인할 사항은?