노트

유틸리티 타입

Utility Types

프런트엔드#ts · 연결된 개념 6개

쉽게 말하면

유틸리티 타입은 이미 있는 회원 정보 양식에서 '비밀번호 칸 빼기', '모든 칸 선택 사항으로' 같은 변형을 한 줄로 만들어 주는 내장 도구예요. 같은 모양을 손으로 다시 적지 않아도 되죠.

비유가 깨지는 곳 칸 하나의 타입을 바꿀 땐 &로 덧붙이면 교체가 아니라 교집합이 돼요. 먼저 Omit으로 지우고 다시 붙여야 해요. 쓰기 가능하게 만드는 반대 도구는 내장이 없어 매핑된 타입으로 만들어요.

유틸리티 타입(Utility Types)은 기존 타입에서 새 타입을 만들어 주는 TypeScript 내장 제네릭 타입이다. 같은 모양을 손으로 다시 선언하지 않게 해 준다.

타입결과
Partial<T>모든 속성을 선택적으로
Required<T>모든 속성을 필수로
Readonly<T>모든 속성을 읽기 전용으로
Pick<T, K>지정한 키만
Omit<T, K>지정한 키를 빼고
Record<K, V>키 K, 값 V인 객체
Exclude<U, X>유니언에서 X를 뺌
ReturnType<F> · Parameters<F>함수의 반환·매개변수 타입
type CreateUserInput = Pick<User, 'name' | 'email'>
type UpdateUserInput = Partial<CreateUserInput>      // PATCH용
type PublicUser = Omit<User, 'password'>
  • 속성 타입을 바꿀 때는 &만으로는 안 된다. { config: unknown } & { config: Layout }은 교체가 아니라 교집합이다. 먼저 Omit으로 지우고 다시 붙인다
type Group = Omit<ApiGroup, 'layout'> & { layout: LayoutConfig }
  • Readonly의 반대(쓰기 가능하게)는 내장이 없어서 매핑된 타입의 -readonly 수정자로 만든다(매핑된 타입과 keyof)
  • 생성/수정/조회용 타입을 도메인 타입 하나에서 파생시키면 필드가 바뀔 때 한 곳만 고치면 된다(DRY 원칙). 단, 화면 편의 타입이 도메인 타입보다 많아지면 오히려 읽기 어렵다

내장 유틸리티는 대부분 매핑된 타입과 조건부 타입으로 구현돼 있다. 기초는 제네릭.

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 템플릿 리터럴 타입

    템플릿 리터럴 타입(Template Literal Types)은 문자열 리터럴 타입을 템플릿 문자열 문법으로 조합해 새 문자열 유니언을 만드는 기능이다. 유니언을 넣으면 가능한 모든 조합이 나온다.

  • 기본형 집착

    전화번호·금액·우선순위 같은 도메인 개념을 끝까지 문자열이나 숫자로만 다루는 냄새. 같은 검증과 포맷 코드가 여기저기 반복되고, 문자열로 모든 걸 표현하는 "stringly typed" 코드가 된다.

  • type과 interface

    type(타입 별칭, Type Alias)과 interface는 둘 다 타입에 이름을 붙이는 방법이다. 객체 모양을 정의할 때는 대부분 바꿔 써도 되지만, 확장 방식과 표현 범위가 다르다.

  • 구조적 타이핑

    구조적 타이핑(Structural Typing)은 타입의 이름이 아니라 모양(가진 속성과 그 타입)이 맞으면 호환된다고 보는 타입 시스템이다. TypeScript가 이 방식을 쓴다. Java처럼 선언된 이름과 상속 관계로 판단하는 방식은 명목적 타이핑(Nominal Typing)이라 한다.

  • 판별 유니언

    판별 유니언(Discriminated Union)은 모든 멤버가 리터럴 타입의 공통 필드(구분자(discriminant), 보통 type·kind·status)를 가진 유니언이다. 그 필드를 검사하면 TypeScript가 나머지 속성까지 자동으로 좁혀 준다.

보기 옵션