Learning
레슨 8 / 10·5개 토픽

Enums과 유틸리티 타입

Numeric Enums

Enum은 관련된 상수들을 하나의 이름 아래 묶어 관리하는 타입입니다. Numeric Enum은 기본적으로 0부터 자동 증가하는 숫자 값을 가집니다.

typescript
// Numeric Enum — 기본값은 0부터 시작
enum Direction {
  Up,      // 0
  Down,    // 1
  Left,    // 2
  Right,   // 3
}

// 시작 값 지정
enum StatusCode {
  OK = 200,
  NotFound = 404,
  ServerError = 500,
}

const move = Direction.Up;       // 0
const status = StatusCode.OK;    // 200

// 역방향 매핑 (숫자 → 이름)
console.log(Direction[0]);       // "Up"
console.log(StatusCode[404]);    // "NotFound"

String Enums과 const Enums

String Enum은 각 멤버에 문자열 값을 할당합니다. 디버깅 시 의미 있는 값을 확인할 수 있어 실무에서 더 자주 사용됩니다. const enum은 컴파일 시 인라인 치환되어 번들 크기를 줄입니다.

typescript
// String Enum
enum Theme {
  Light = "light",
  Dark = "dark",
  System = "system",
}

// 함수에서 활용
function applyTheme(theme: Theme): void {
  console.log("테마 적용: " + theme);
}
applyTheme(Theme.Dark);  // "테마 적용: dark"

// const enum — 컴파일 시 값으로 치환됨
const enum LogLevel {
  Debug = "DEBUG",
  Info = "INFO",
  Warn = "WARN",
  Error = "ERROR",
}

// 컴파일 후: const level = "INFO"
const level = LogLevel.Info;

객체 변환 유틸리티 타입

TypeScript는 기존 타입을 변환하여 새로운 타입을 만드는 내장 유틸리티 타입을 제공합니다. Partial, Required, Readonly는 객체의 모든 속성을 일괄 변환합니다.

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

// Partial<T> — 모든 속성을 선택적(optional)으로
type UpdateData = Partial<User>;
// { name?: string; email?: string; age?: number }

function updateUser(id: number, data: Partial<User>): void {
  // 일부 필드만 업데이트 가능
}
updateUser(1, { name: "김철수" });  // OK

// Required<T> — 모든 속성을 필수로
interface Config {
  host?: string;
  port?: number;
}
type StrictConfig = Required<Config>;
// { host: string; port: number }

// Readonly<T> — 모든 속성을 읽기 전용으로
type FrozenUser = Readonly<User>;
const user: FrozenUser = { name: "Alice", email: "a@b.com", age: 25 };
// user.name = "Bob";  // Error: readonly 속성

Pick, Omit, Record

typescript
interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
  category: string;
}

// Pick<T, K> — 원하는 속성만 선택
type ProductSummary = Pick<Product, "id" | "name" | "price">;
// { id: number; name: string; price: number }

// Omit<T, K> — 특정 속성을 제외
type ProductInput = Omit<Product, "id">;
// { name: string; price: number; description: string; category: string }

// Record<K, V> — 키-값 쌍의 객체 타입
type CategoryMap = Record<string, Product[]>;

const catalog: CategoryMap = {
  electronics: [{ id: 1, name: "노트북", price: 1500000, description: "...", category: "electronics" }],
  books: [],
};

// Record로 상태 맵 만들기
type Status = "loading" | "success" | "error";
type StatusFlags = Record<Status, boolean>;
// { loading: boolean; success: boolean; error: boolean }

함수·조건부 유틸리티 타입

ReturnTypeParameters는 함수 타입에서 반환 타입과 매개변수 타입을 추출합니다. Exclude, Extract, NonNullable은 Union 타입을 필터링합니다.

typescript
// ReturnType<T> — 함수의 반환 타입 추출
function createUser(name: string, age: number) {
  return { id: Date.now(), name, age, createdAt: new Date() };
}
type NewUser = ReturnType<typeof createUser>;
// { id: number; name: string; age: number; createdAt: Date }

// Parameters<T> — 함수의 매개변수 타입 (튜플)
type CreateUserParams = Parameters<typeof createUser>;
// [name: string, age: number]

// Exclude<T, U> — Union에서 U에 해당하는 타입 제거
type AllEvents = "click" | "focus" | "blur" | "scroll";
type MouseEvents = Exclude<AllEvents, "focus" | "blur">;
// "click" | "scroll"

// Extract<T, U> — Union에서 U에 해당하는 타입만 추출
type FocusEvents = Extract<AllEvents, "focus" | "blur">;
// "focus" | "blur"

// NonNullable<T> — null과 undefined 제거
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// string
💡

실무에서 가장 자주 쓰는 유틸리티 타입은 Partial(업데이트 함수), Pick/Omit(API 응답 가공), Record(맵 구조)입니다. Enum은 상수 그룹 관리에 편리하지만, Union 타입(type Theme = "light" | "dark")이 더 가벼운 대안이 되기도 합니다.