SHIN STORYSHIN STORY
홈포스트C#TypeScriptNext.jsNode.js시리즈
</>SHIN STORY

sdf

탐색

  • 홈
  • 모든 포스트
  • 시리즈
  • 검색

카테고리

  • C#
  • TypeScript
  • Next.js
  • Node.js
  • 알고리즘
  • 개발 도구

© 2025 Shin Blog. All rights reserved.

GitHubRSS
목록으로
TypeScript#TypeScript

TypeScript 팁 #6 — 매핑 타입으로 타입 변환하기

SHIN

2025년 4월 25일5분 읽기0
📚

TypeScript 실전 팁 10선

10편
  1. 5TypeScript 팁 #5 — 타입 가드로 런타임 타입 좁히기
  2. TypeScript 팁 #6 — 매핑 타입으로 타입 변환하기현재
  3. 10TypeScript 팁 #1 — strict 모드를 반드시 켜야 하는 이유
  4. 10TypeScript 팁 #2 — 유틸리티 타입 완전 정복
  5. 10TypeScript 팁 #3 — 판별 유니온으로 타입 안전한 상태 관리
  6. 10TypeScript 팁 #4 — 제네릭 제약 조건과 infer 활용
  7. 10TypeScript 팁 #7 — 템플릿 리터럴 타입으로 문자열 타입 조작
  8. 10TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기
  9. 10TypeScript 팁 #9 — 타입 안전한 에러 처리 패턴
  10. 10TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

TypeScript 팁 #6 — 매핑 타입으로 타입 변환하기

매핑 타입은 기존 타입의 각 프로퍼티를 순회하며 새로운 타입을 만드는 강력한 도구입니다.

기본 문법

CODE
// [K in keyof T]: 타입 T의 모든 키를 순회
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K]
}

type MyPartial<T> = {
  [K in keyof T]?: T[K]
}

type MyRequired<T> = {
  [K in keyof T]-?: T[K]  // ? 제거 (Required)
}

값 타입 변환

CODE
// 모든 값을 string으로
type Stringify<T> = {
  [K in keyof T]: string
}

// 모든 값을 배열로
type Arrayify<T> = {
  [K in keyof T]: T[K][]
}

interface Point { x: number; y: number }

type StringPoint = Stringify<Point>  // { x: string; y: string }
type ArrayPoint  = Arrayify<Point>   // { x: number[]; y: number[] }

키 재매핑 (as 절)

TypeScript 4.1+ 에서 as로 키를 변환할 수 있습니다.

CODE
// 모든 키에 get 접두사 추가
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}

interface User { name: string; age: number }

type UserGetters = Getters<User>
// {
//   getName: () => string
//   getAge:  () => number
// }

특정 타입의 키만 필터링

CODE
// string 값만 가진 키 추출
type StringKeys<T> = {
  [K in keyof T]: T[K] extends string ? K : never
}[keyof T]

interface Mixed {
  id: number
  name: string
  email: string
  active: boolean
}

type StrKeys = StringKeys<Mixed>  // 'name' | 'email'

// 활용: 문자열 필드만 있는 타입
type StringFields<T> = Pick<T, StringKeys<T>>
type MixedStrings = StringFields<Mixed>  // { name: string; email: string }

이벤트 핸들러 자동 생성

CODE
// 이벤트 맵에서 on-핸들러 타입 자동 생성
type EventHandlers<T extends Record<string, any>> = {
  [K in keyof T as `on${Capitalize<string & K>}`]?: (event: T[K]) => void
}

interface AppEvents {
  click:  { x: number; y: number }
  submit: { formData: FormData }
  resize: { width: number; height: number }
}

type Handlers = EventHandlers<AppEvents>
// {
//   onClick?:  (event: { x: number; y: number }) => void
//   onSubmit?: (event: { formData: FormData }) => void
//   onResize?: (event: { width: number; height: number }) => void
// }

Form 상태 타입 자동 생성

CODE
type FormState<T> = {
  values: T
  errors: Partial<Record<keyof T, string>>
  touched: Partial<Record<keyof T, boolean>>
  dirty: boolean
  isSubmitting: boolean
}

interface LoginForm {
  email: string
  password: string
}

type LoginFormState = FormState<LoginForm>
// values.email, errors.email, touched.email 등이 모두 타입 안전

불변 중첩 객체

CODE
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}

const config: DeepReadonly<{ db: { host: string; port: number } }> = {
  db: { host: 'localhost', port: 5432 }
}

config.db.host = 'prod'  // ❌ 깊은 곳까지 읽기 전용

매핑 타입은 반복적인 타입 선언을 자동화하고, 코드 변경 시 타입이 자동으로 업데이트되게 해줍니다.

공유
S

SHIN

.NET 개발자입니다

GitHub

이전 포스트

TypeScript 팁 #5 — 타입 가드로 런타임 타입 좁히기

다음 포스트

TypeScript 팁 #7 — 템플릿 리터럴 타입으로 문자열 타입 조작

TypeScript 팁 #7 — 템플릿 리터럴 타입으로 문자열 타입 조작

같은 카테고리 포스트

TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

TypeScript 팁 #10 — 타입 성능 최적화와 실무 패턴

2025년 5월 3일· 3분
TypeScript 팁 #9 — 타입 안전한 에러 처리 패턴

TypeScript 팁 #9 — 타입 안전한 에러 처리 패턴

2025년 5월 1일· 2분
TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기

TypeScript 팁 #8 — 선언 병합과 모듈 보강으로 타입 확장하기

2025년 4월 29일· 2분

댓글