타입스크립트 고급 타입 시스템: 제네릭·유니온·조건부 타입

💡 핵심 요약 (Executive Summary)

본 가이드는 typescript 핵심 가이드 및 실전 아키텍처의 핵심 개념, 실전 구성 명령어 및 아키텍처 베스트 프랙티스를 다룹니다. 클라우드 네이티브 및 인프라 엔지니어링 실무에 즉시 활용 가능하도록 체계적으로 정리했습니다.

📑 Table of Contents
Utility Type

TypeScript의 **유틸리티 타입(Utility Types)**은 이미 정의된 타입들을 변형하거나 새로운 타입을 쉽게 생성할 수 있도록 도와주는 강력한 도구입니다. 자주 사용되는 유틸리티 타입은 Partial, Readonly, Pick, Omit 등이 있습니다. 아래에서 각각의 유틸리티 타입에 대한 간단한 설명과 예제를 살펴보겠습니다.

1. Partial

Partial는 주어진 타입 T의 모든 속성을 선택적(optional)으로 만드는 타입을 생성합니다.

ts
interface User {
  name: string;
  age: number;
  email: string;
}

function updateUser(user: User, updates: Partial<User>): User {
  return { ...user, ...updates };
}

const user: User = {
  name: "John",
  age: 30,
  email: "[email protected]",
};

// Partial을 사용하여 필요한 속성만 업데이트 가능
const updatedUser = updateUser(user, { age: 31 });
console.log(updatedUser);
// 출력: { name: 'John', age: 31, email: '[email protected]' }
2. Readonly

Readonly는 주어진 타입 T의 모든 속성을 읽기 전용(readonly)으로 만드는 타입을 생성합니다. 즉, 해당 속성들을 변경할 수 없게 합니다.

ts
interface User {
  name: string;
  age: number;
}

const user: Readonly<User> = {
  name: "Alice",
  age: 25,
};

// user.name = "Bob";  // 오류: 'name'은 읽기 전용 속성입니다.
console.log(user);
// 출력: { name: 'Alice', age: 25 }
3. Pick

Pick는 타입 T에서 속성 K들만 선택하여 새로운 타입을 생성합니다. 여기서 K는 T의 키들 중 일부입니다.

ts
interface User {
  name: string;
  age: number;
  email: string;
}

type UserInfo = Pick<User, "name" | "email">;

const userInfo: UserInfo = {
  name: "Alice",
  email: "[email protected]",
};

console.log(userInfo);
// 출력: { name: 'Alice', email: '[email protected]' }
4. Omit

Omit는 타입 T에서 속성 K들을 제외한 나머지 속성으로 새로운 타입을 생성합니다.

ts
interface User {
  name: string;
  age: number;
  email: string;
}

type UserWithoutEmail = Omit<User, "email">;

const userWithoutEmail: UserWithoutEmail = {
  name: "Bob",
  age: 28,
};

console.log(userWithoutEmail);
// 출력: { name: 'Bob', age: 28 }
5. Record

Record는 키 타입 K와 값 타입 T를 사용하여 객체 타입을 생성합니다. 즉, K는 키의 타입, T는 값의 타입입니다.

ts
type Role = "admin" | "user" | "guest";
interface UserInfo {
  name: string;
  age: number;
}

const users: Record<Role, UserInfo> = {
  admin: { name: "John", age: 30 },
  user: { name: "Jane", age: 25 },
  guest: { name: "Visitor", age: 22 },
};

console.log(users);
// 출력:
// {
//   admin: { name: 'John', age: 30 },
//   user: { name: 'Jane', age: 25 },
//   guest: { name: 'Visitor', age: 22 }
// }
6. Required

Required는 타입 T의 모든 선택적 속성을 필수적으로 바꿔주는 타입을 생성합니다.

ts
interface User {
  name: string;
  age?: number;
}

const user1: Required<User> = {
  name: "John",
  age: 30, // age는 필수 속성으로 변경됨
};

// const user2: Required<User> = { name: "John" }; // 오류: 'age' 속성이 필요합니다.
7. NonNullable

NonNullable는 타입 T에서 null과 undefined를 제외한 타입을 생성합니다.

ts
type Name = string | null | undefined;

const validName: NonNullable<Name> = "Alice";
// const invalidName: NonNullable<Name> = null; // 오류: 'null'은 'NonNullable<string>' 타입에 할당할 수 없습니다.
8. ReturnType

ReturnType는 함수 타입 T의 반환 타입을 추출합니다.

ts
function getUserInfo() {
  return { name: "Alice", age: 30 };
}

type UserInfo = ReturnType<typeof getUserInfo>;

const user: UserInfo = {
  name: "Alice",
  age: 30,
};

console.log(user);
// 출력: { name: 'Alice', age: 30 }
9. Extract

Extract는 T에서 U에 해당하는 타입만 추출합니다.

ts
type MixedType = string | number | boolean;

type OnlyStringOrNumber = Extract<MixedType, string | number>;

const value: OnlyStringOrNumber = 42;
// const invalidValue: OnlyStringOrNumber = true; // 오류: 'boolean'은 'string | number' 타입에 할당할 수 없습니다.
10. Exclude

Exclude는 T에서 U에 해당하는 타입을 제외한 나머지 타입을 생성합니다.

ts
type MixedType = string | number | boolean;

type ExcludeBoolean = Exclude<MixedType, boolean>;

const value: ExcludeBoolean = "Hello";
// const invalidValue: ExcludeBoolean = true; // 오류: 'boolean'은 'string | number' 타입에 할당할 수 없습니다.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *