TypeScriptTypeScript 기초 · 6기초

유틸리티 타입 — 타입 변환 도구 모음

TypeScript유틸리티타입PartialPickOmitRecord

유틸리티 타입이란?

기존 타입을 변환해 새 타입을 만드는 내장 도구입니다. 반복적인 타입 정의를 줄여줍니다.

interface User {
    id: number;
    name: string;
    email: string;
    password: string;
    createdAt: Date;
}

Partial<T>: 모든 속성을 선택적으로

type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; ... }

// PATCH 요청: 일부 필드만 업데이트
function updateUser(id: number, changes: Partial<User>): User {
    // changes는 어떤 필드든 있어도 없어도 됨
    return { ...existingUser, ...changes };
}

updateUser(1, { name: "새 이름" });   // ✅
updateUser(1, { email: "new@example.com", name: "새 이름" });  // ✅

Required<T>: 모든 속성을 필수로

interface Config {
    host?: string;
    port?: number;
    debug?: boolean;
}

type RequiredConfig = Required<Config>;
// { host: string; port: number; debug: boolean; }

Readonly<T>: 모든 속성을 읽기 전용으로

type ReadonlyUser = Readonly<User>;

const user: ReadonlyUser = {
    id: 1, name: "철수", email: "kim@example.com",
    password: "secret", createdAt: new Date(),
};

// user.name = "영희";  // ❌ 읽기 전용

Pick<T, K>: 특정 속성만 선택

// 공개 프로필: 민감한 정보 제외
type PublicUser = Pick<User, "id" | "name" | "email">;
// { id: number; name: string; email: string; }

// API 응답에서 필요한 필드만
type UserSummary = Pick<User, "id" | "name">;

Omit<T, K>: 특정 속성 제외

// 비밀번호와 생성일 제외
type SafeUser = Omit<User, "password" | "createdAt">;
// { id: number; name: string; email: string; }

// 새 사용자 생성: ID는 서버에서 생성
type CreateUserDto = Omit<User, "id" | "createdAt">;

Record<K, V>: 키-값 맵 타입

// 키: string, 값: number인 객체
type ScoreMap = Record<string, number>;
const scores: ScoreMap = { 철수: 85, 영희: 92 };

// 열거형 키
type Status = "active" | "inactive" | "pending";
type StatusLabel = Record<Status, string>;

const labels: StatusLabel = {
    active: "활성",
    inactive: "비활성",
    pending: "대기",
};

Exclude<T, U>와 Extract<T, U>

type AllStatus = "active" | "inactive" | "pending" | "banned";

// banned를 제외
type NormalStatus = Exclude<AllStatus, "banned">;
// "active" | "inactive" | "pending"

// 특정 상태만 추출
type ActiveOrPending = Extract<AllStatus, "active" | "pending">;
// "active" | "pending"

ReturnType<T>와 Parameters<T>

function fetchUser(id: number, token: string): Promise<User> {
    return fetch(`/api/users/${id}`).then(r => r.json());
}

// 함수 반환 타입 추출
type FetchUserReturn = ReturnType<typeof fetchUser>;
// Promise<User>

// 함수 매개변수 타입 추출
type FetchUserParams = Parameters<typeof fetchUser>;
// [id: number, token: string]

실전 조합 패턴

// CRUD 작업에서 자주 쓰는 패턴
interface Product {
    id: string;
    name: string;
    price: number;
    stock: number;
    createdAt: Date;
    updatedAt: Date;
}

// 생성: id, 날짜는 서버에서 생성
type CreateProductDto = Omit<Product, "id" | "createdAt" | "updatedAt">;

// 수정: 모든 필드 선택적 (id는 경로 파라미터로)
type UpdateProductDto = Partial<Omit<Product, "id" | "createdAt" | "updatedAt">>;

// 응답: 전체
type ProductResponse = Readonly<Product>;

// 목록: 일부만
type ProductSummary = Pick<Product, "id" | "name" | "price">;

정리

유틸리티 타입변환 내용
Partial<T>모든 속성 선택적
Required<T>모든 속성 필수
Readonly<T>모든 속성 읽기 전용
Pick<T, K>특정 속성만 선택
Omit<T, K>특정 속성 제외
Record<K, V>키-값 맵 타입
Exclude<T, U>유니온에서 특정 타입 제거
Extract<T, U>유니온에서 특정 타입 추출
ReturnType<T>함수 반환 타입 추출

다음 편에서는 타입 좁히기와 고급 패턴 — 조건부 타입, 맵드 타입, 타입 가드를 배웁니다.

궁금한 점이 있으신가요?

협업·의뢰는 아래로, 가벼운 소통은 인스타그램 @bluefox._.hi도 환영이에요.