7장: 고급 타입 - 타입스크립트의 힘 제대로 활용하기
TypeScript는 기본 타입을 넘어, 기존 타입을 변환하거나 조합하여 더 정교하고 유연한 타입을 만들 수 있는 다양한 고급 타입 기능들을 제공합니다. 이를 통해 반복적인 타입 정의를 줄이고, 코드의 표현력을 극대화할 수 있습니다.
1. 유틸리티 타입 (Utility Types)
유틸리티 타입은 기존 타입을 바탕으로 새로운 타입을 만들어내는, TypeScript에 내장된 특별한 제네릭 타입입니다. 매우 유용하고 자주 사용됩니다.
Partial<T>: 타입T의 모든 속성을 선택적(optional,?)으로 만듭니다. 객체의 일부만 업데이트할 때 유용합니다.interface User { id: number; name: string; email: string; } type PartialUser = Partial<User>; // { id?: number; name?: string; email?: string; }Readonly<T>: 타입T의 모든 속성을 읽기 전용(readonly)으로 만듭니다. 불변 객체를 만들 때 사용합니다.type ReadonlyUser = Readonly<User>;Pick<T, K>: 타입T에서K속성들만 골라 새로운 타입을 만듭니다.type UserPreview = Pick<User, 'id' | 'name'>; // { id: number; name: string; }Omit<T, K>: 타입T에서K속성들만 제외하고 새로운 타입을 만듭니다.type UserWithoutEmail = Omit<User, 'email'>; // { id: number; name: string; }Record<K, T>: 키(key)가K타입이고 값(value)이T타입인 객체 타입을 만듭니다.type UserRoles = 'admin' | 'editor' | 'guest'; const rolePermissions: Record<UserRoles, boolean> = { admin: true, editor: true, guest: false, };
2. 타입 가드 (Type Guards)
타입 가드는 특정 스코프(scope) 내에서 변수의 타입을 더 구체적인 타입으로 좁혀주는(narrowing) 표현식입니다. unknown이나 유니언 타입을 다룰 때 필수적입니다.
typeof타입 가드:function printValue(value: string | number) { if (typeof value === 'string') { console.log(value.toUpperCase()); // 이 블록 안에서 value는 string 타입 } else { console.log(value.toFixed(2)); // 이 블록 안에서 value는 number 타입 } }instanceof타입 가드:class Fish { swim() {} } class Bird { fly() {} } function move(animal: Fish | Bird) { if (animal instanceof Fish) { animal.swim(); // animal은 Fish 타입 } else { animal.fly(); // animal은 Bird 타입 } }사용자 정의 타입 가드 (User-Defined Type Guards):
is키워드를 사용하여 타입을 판별하는 함수를 직접 만들 수 있습니다.interface Cat { meow(): void; } interface Dog { bark(): void; } // 이 함수는 boolean을 반환하며, true일 경우 pet이 Cat 타입임을 보장 function isCat(pet: Cat | Dog): pet is Cat { return (pet as Cat).meow !== undefined; } function makeSound(pet: Cat | Dog) { if (isCat(pet)) { pet.meow(); // pet은 Cat 타입으로 좁혀짐 } else { pet.bark(); // pet은 Dog 타입으로 좁혀짐 } }
3. 그 외 고급 타입
인덱스 시그니처 (Index Signatures): 객체가 임의의 키를 가질 수 있을 때 사용합니다.
interface StringArray { [index: number]: string; // 키는 number, 값은 string } const arr: StringArray = ['a', 'b', 'c'];매핑된 타입 (Mapped Types): 기존 타입을 기반으로, 각 속성을 변환하여 새로운 타입을 만듭니다. 유틸리티 타입들은 대부분 매핑된 타입을 사용하여 구현됩니다.
type Flags = { [K in keyof User]: boolean }; // User의 모든 속성을 boolean 타입으로 변환 // { id: boolean; name: boolean; email: boolean; }조건부 타입 (Conditional Types): 삼항 연산자처럼, 타입에 조건을 적용하여 다른 타입을 반환합니다.
type IsString<T> = T extends string ? true : false; type A = IsString<string>; // true type B = IsString<number>; // false
4. 연습 문제
문제 1: 유틸리티 타입 활용하기
- 요구사항: 아래
Book인터페이스를 바탕으로, 유틸리티 타입을 사용하여 다음 타입들을 만들어보세요.interface Book { id: number; title: string; author: string; publishedYear: number; isbn: string; }BookToCreate:id속성이 제외된 타입 (새 책을 만들 때 사용)BookToUpdate: 모든 속성이 선택적인 타입 (책 정보를 부분적으로 수정할 때 사용)BookSummary:title과author속성만 가진 타입
문제 1 정답 예시
// 1. Omit 사용
type BookToCreate = Omit<Book, 'id'>;
// 2. Partial 사용
type BookToUpdate = Partial<Book>;
// 3. Pick 사용
type BookSummary = Pick<Book, 'title' | 'author'>;
문제 2: 사용자 정의 타입 가드 만들기
- 요구사항: API 응답 객체를 나타내는
SuccessResponse와ErrorResponse인터페이스가 있습니다. 이 두 타입을 구분하는 사용자 정의 타입 가드 함수isSuccess를 만드세요.interface SuccessResponse { status: 'success'; data: any; } interface ErrorResponse { status: 'error'; errorCode: number; errorMessage: string; } type ApiResponse = SuccessResponse | ErrorResponse; - 힌트:
response.status === 'success'조건을 확인하여response is SuccessResponse를 반환하도록 함수를 작성하세요.
문제 2 정답 예시
function isSuccess(response: ApiResponse): response is SuccessResponse {
return response.status === 'success';
}
function handleApiResponse(response: ApiResponse) {
if (isSuccess(response)) {
// 이 블록에서 response는 SuccessResponse 타입
console.log('Data:', response.data);
} else {
// 이 블록에서 response는 ErrorResponse 타입
console.error(`Error ${response.errorCode}: ${response.errorMessage}`);
}
}
'백엔드 > 타입스크립트' 카테고리의 다른 글
| [TypeScript] 8장: 실전 프로젝트 - 클래스 기반 Todo 리스트 만들기 (0) | 2025.09.18 |
|---|---|
| [TypeScript] 6장: 제네릭 - 재사용 가능한 타입 만들기 (0) | 2025.09.17 |
| [TypeScript] 5장: 열거형과 리터럴 타입 - 정해진 값만 허용하기 (0) | 2025.09.17 |
| [TypeScript] 4장: 인터페이스와 타입 별칭 - 타입에 이름 붙이기 (0) | 2025.09.17 |
| [TypeScript] 3장: 함수와 객체 - 코드의 기본 단위 타입 정의하기 (0) | 2025.09.17 |
| [TypeScript] 2장: 핵심 기본 타입 - 데이터의 종류 정의하기 (0) | 2025.09.17 |
| [TypeScript] 1장: TypeScript 소개 및 개발 환경 설정 (0) | 2025.09.17 |