TypeScriptTypeScript 기초강의 8개 중 6번째난이도 기초

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

발행 읽는 시간 약 1 분

  • TypeScript
  • 유틸리티타입
  • Partial
  • Pick
  • Omit
  • Record

강의 소개

TypeScript 내장 유틸리티 타입을 배웁니다. Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract 등을 실전에서 활용하는 방법을 익힙니다.

유틸리티 타입이란?#

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

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

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

TypeScript
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>: 모든 속성을 필수로#

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

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

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

TypeScript
type ReadonlyUser = Readonly<User>;

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

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

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

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

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

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

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

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

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

TypeScript
// 키: 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>#

TypeScript
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>#

TypeScript
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]

실전 조합 패턴#

TypeScript
// 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>함수 반환 타입 추출

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

Follow · Ask · Work

이 글이 도움이 됐다면

짧은 작업 기록과 데모는 인스타그램에 올립니다. 만들고 싶은 것이 있다면 프로젝트 의뢰나 협업 제안도 편하게 보내 주세요.

글쓴이

파란여우

직접 만든 AI 앱·제품의 개발·배포를 공개하는 실전형 테크 크리에이터

파란여우 소개 Instagram @bluefox._.hi

이어서 보기

만들고 싶은 것이 있다면 프로젝트 의뢰로 알려 주세요.