Examples Verified (100%)
매핑된 타입
준비 중
이 기능은 향후 릴리스에 계획되어 있습니다.
매핑된 타입을 사용하면 속성을 반복하여 한 타입을 다른 타입으로 변환할 수 있습니다. 타입을 위한 "map" 연산이라고 생각하세요—각 속성에 변환을 적용하여 기존 타입을 기반으로 프로그래밍 방식으로 새 타입을 만들 수 있습니다.
매핑된 타입 이해하기
매핑된 타입은 타입의 키를 반복하고 변환을 적용하여 새 타입을 만듭니다:
Verifiedtype MappedType<T> = {
[K in keyof T]: Transformation<T[K]>
}
기본 문법
Verified# T의 키를 반복
type ReadonlyType<T> = {
readonly [K in keyof T]: T[K]
}
# 모든 속성을 선택적으로 만들기
type OptionalType<T> = {
[K in keyof T]?: T[K]
}
# 모든 속성을 필수로 만들기
type RequiredType<T> = {
[K in keyof T]-?: T[K]
}
keyof 연산자
keyof 연산자는 타입의 모든 키를 유니온으로 가져옵니다:
type User = {
id: Integer,
name: String,
email: String
}
type UserKeys = keyof User # "id" | "name" | "email"
# 매핑된 타입에서 사용
type UserValues<T> = {
[K in keyof T]: T[K]
}
기본 매핑된 타입 패턴
속성을 읽기 전용으로 만들기
Verified# 모든 속성을 읽기 전용으로 만들기
type Readonly<T> = {
readonly [K in keyof T]: T[K]
}
type User = {
id: Integer,
name: String,
email: String
}
type ReadonlyUser = Readonly<User>
# {
# readonly id: Integer,
# readonly name: String,
# readonly email: String
# }
# 사용법
user: ReadonlyUser = { id: 1, name: "Alice", email: "alice@example.com" }
# user.name = "Bob" # 에러: 읽기 전용 속성에 할당할 수 없음
속성을 선택적으로 만들기
Verified# 모든 속성을 선택적으로 만들기
type Partial<T> = {
[K in keyof T]?: T[K]
}
type User = {
id: Integer,
name: String,
email: String
}
type PartialUser = Partial<User>
# {
# id?: Integer,
# name?: String,
# email?: String
# }
# 사용법 - 모든 속성이 선택적
partial_user: PartialUser = { name: "Alice" } # OK
partial_user2: PartialUser = {} # OK
속성을 필수로 만들기
Verified# 선택적 수정자 제거
type Required<T> = {
[K in keyof T]-?: T[K]
}
type UserUpdate = {
id?: Integer,
name?: String,
email?: String
}
type RequiredUserUpdate = Required<UserUpdate>
# {
# id: Integer,
# name: String,
# email: String
# }
속성 변환
속성 타입 변환
Verified# 모든 속성을 배열로 변환
type Arrayify<T> = {
[K in keyof T]: Array<T[K]>
}
type User = {
id: Integer,
name: String
}
type ArrayUser = Arrayify<User>
# {
# id: Array<Integer>,
# name: Array<String>
# }
# 모든 속성을 프로미스로 변환
type Promisify<T> = {
[K in keyof T]: Promise<T[K]>
}
# 모든 속성을 널러블로 변환
type Nullable<T> = {
[K in keyof T]: T[K] | nil
}
수정자 추가 또는 제거
Verified# 읽기 전용 추가
type AddReadonly<T> = {
+readonly [K in keyof T]: T[K]
}
# 읽기 전용 제거
type RemoveReadonly<T> = {
-readonly [K in keyof T]: T[K]
}
# 선택적으로 만들기
type MakeOptional<T> = {
[K in keyof T]+?: T[K]
}
# 필수로 만들기
type MakeRequired<T> = {
[K in keyof T]-?: T[K]
}
키 필터링
특정 속성 선택
Verified# 지정된 키만 선택
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
type User = {
id: Integer,
name: String,
email: String,
password: String
}
type PublicUser = Pick<User, "id" | "name">
# {
# id: Integer,
# name: String
# }
# 사용법
public_user: PublicUser = { id: 1, name: "Alice" }
특정 속성 제외
Verified# 지정된 키 제외
type Omit<T, K extends keyof T> = {
[P in Exclude<keyof T, K>]: T[P]
}
type User = {
id: Integer,
name: String,
email: String,
password: String
}
type UserWithoutPassword = Omit<User, "password">
# {
# id: Integer,
# name: String,
# email: String
# }
# 여러 속성 제외
type UserBasic = Omit<User, "password" | "email">
# {
# id: Integer,
# name: String
# }
조건부 매핑된 타입
매핑된 타입을 조건부 타입과 결합:
Verified# 조건에 따라 속성을 읽기 전용으로 만들기
type ConditionalReadonly<T> = {
readonly [K in keyof T]: T[K] extends Function ? T[K] : readonly T[K]
}
# 조건에 따라 속성을 널러블로 만들기
type ConditionalNullable<T> = {
[K in keyof T]: T[K] extends String ? T[K] | nil : T[K]
}
# 함수 제거
type RemoveFunctions<T> = {
[K in keyof T as T[K] extends Function ? never : K]: T[K]
}
키 리매핑
매핑하는 동안 속성 키 변환:
Verified# 모든 키에 접두사 추가
type Prefixed<T, Prefix extends String> = {
[K in keyof T as `${Prefix}${K}`]: T[K]
}
type User = {
id: Integer,
name: String
}
type PrefixedUser = Prefixed<User, "user_">
# {
# user_id: Integer,
# user_name: String
# }
# 키를 대문자로 변환
type Uppercased<T> = {
[K in keyof T as Uppercase<K>]: T[K]
}
# getter 추가
type WithGetters<T> = {
[K in keyof T as `get${Capitalize<K>}`]: () => T[K]
}
type User = { name: String, age: Integer }
type UserWithGetters = WithGetters<User>
# {
# getName: () => String,
# getAge: () => Integer
# }
실용적인 예제
DTO 패턴
Verified# 데이터 전송 객체 - 모든 속성이 선택적이고 널러블이 됨
type DTO<T> = {
[K in keyof T]?: T[K] | nil
}
# API 응답 - 데이터 래핑
type APIWrapper<T> = {
[K in keyof T]: {
value: T[K],
updated_at: Time
}
}
type User = {
name: String,
email: String
}
type UserDTO = DTO<User>
# {
# name?: String | nil,
# email?: String | nil
# }
type UserAPI = APIWrapper<User>
# {
# name: { value: String, updated_at: Time },
# email: { value: String, updated_at: Time }
# }
폼 핸들러
Verified# 속성을 폼 필드로 변환
type FormFields<T> = {
[K in keyof T]: {
value: T[K],
error: String | nil,
touched: Boolean
}
}
# 폼 값만
type FormValues<T> = {
[K in keyof T]: T[K]
}
# 폼 이벤트 핸들러
type FormHandlers<T> = {
[K in keyof T as `on${Capitalize<K>}Change`]: (value: T[K]) => void
}
type LoginForm = {
username: String,
password: String
}
type LoginFields = FormFields<LoginForm>
# {
# username: { value: String, error: String | nil, touched: Boolean },
# password: { value: String, error: String | nil, touched: Boolean }
# }
type LoginHandlers = FormHandlers<LoginForm>
# {
# onUsernameChange: (value: String) => void,
# onPasswordChange: (value: String) => void
# }
데이터베이스 모델
Verified# 모델에 타임스탬프 추가
type WithTimestamps<T> = T & {
created_at: Time,
updated_at: Time
}
# 업데이트를 위해 모델을 부분적으로 만들기
type UpdateModel<T> = Partial<Omit<T, "id" | "created_at">>
# 데이터베이스 메타데이터 추가
type DBModel<T> = {
[K in keyof T]: {
value: T[K],
column_name: String,
dirty: Boolean
}
}
type User = {
id: Integer,
name: String,
email: String
}
type TimestampedUser = WithTimestamps<User>
# {
# id: Integer,
# name: String,
# email: String,
# created_at: Time,
# updated_at: Time
# }
type UserUpdate = UpdateModel<User>
# {
# name?: String,
# email?: String
# }
이벤트 핸들러
Verified# 모든 속성에 대한 이벤트 핸들러 생성
type EventHandlers<T> = {
[K in keyof T as `on${Capitalize<K>}Updated`]: (value: T[K]) => void
}
# 모든 속성에 대한 검증자 생성
type Validators<T> = {
[K in keyof T]: (value: T[K]) => Boolean
}
# 모든 속성에 대한 직렬화기 생성
type Serializers<T> = {
[K in keyof T]: (value: T[K]) => String
}
type Product = {
name: String,
price: Float,
stock: Integer
}
type ProductHandlers = EventHandlers<Product>
# {
# onNameUpdated: (value: String) => void,
# onPriceUpdated: (value: Float) => void,
# onStockUpdated: (value: Integer) => void
# }
type ProductValidators = Validators<Product>
# {
# name: (value: String) => Boolean,
# price: (value: Float) => Boolean,
# stock: (value: Integer) => Boolean
# }
깊은 매핑된 타입
중첩된 객체에 재귀적으로 매핑 적용:
Verified# 깊은 읽기 전용
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends Hash<any, any>
? DeepReadonly<T[K]>
: T[K]
}
# 깊은 부분
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends Hash<any, any>
? DeepPartial<T[K]>
: T[K]
}
# 깊은 필수
type DeepRequired<T> = {
[K in keyof T]-?: T[K] extends Hash<any, any>
? DeepRequired<T[K]>
: T[K]
}
type NestedUser = {
profile: {
name: String,
settings: {
theme: String,
notifications: Boolean
}
}
}
type DeepReadonlyUser = DeepReadonly<NestedUser>
# 모든 중첩 속성이 읽기 전용이 됨
매핑된 타입 결합
여러 매핑 결합:
Verified# 읽기 전용과 부분
type ReadonlyPartial<T> = Readonly<Partial<T>>
# 읽기 전용과 필수
type ReadonlyRequired<T> = Readonly<Required<T>>
# 널러블과 부분
type NullablePartial<T> = {
[K in keyof T]?: T[K] | nil
}
# Pick과 Partial
type PartialPick<T, K extends keyof T> = Partial<Pick<T, K>>
type User = {
id: Integer,
name: String,
email: String,
password: String
}
type SafeUserUpdate = ReadonlyPartial<Omit<User, "id">>
# {
# readonly name?: String,
# readonly email?: String,
# readonly password?: String
# }
타입 안전 빌더
매핑된 타입을 사용하여 타입 안전 빌더 생성:
Verified# 모든 속성이 설정되도록 보장하는 빌더
type Builder<T> = {
[K in keyof T as `with${Capitalize<K>}`]: (value: T[K]) => Builder<T>
} & {
build: () => T
}
# 플루언트 API
type FluentAPI<T> = {
[K in keyof T]: (value: T[K]) => FluentAPI<T>
} & {
get: () => T
}
# 사용 예제
type User = {
name: String,
email: String,
age: Integer
}
type UserBuilder = Builder<User>
# {
# withName: (value: String) => UserBuilder,
# withEmail: (value: String) => UserBuilder,
# withAge: (value: Integer) => UserBuilder,
# build: () => User
# }
모범 사례
1. 설명적인 이름 사용
Verified# 좋음: 명확한 목적
type ReadonlyUser = Readonly<User>
type PartialUpdate = Partial<UserUpdate>
type PublicProfile = Pick<User, "id" | "name">
# 덜 좋음: 일반적인 이름
type UserType1 = Readonly<User>
type UserType2 = Partial<UserUpdate>
2. 재사용 가능한 매핑된 타입 생성
Verified# 좋음: 재사용 가능한 유틸리티
type WithTimestamps<T> = T & { created_at: Time, updated_at: Time }
type WithSoftDelete<T> = T & { deleted_at: Time | nil }
type WithMetadata<T> = T & { metadata: Hash<String, String> }
# 구성하기
type FullModel<T> = WithTimestamps<WithSoftDelete<WithMetadata<T>>>
3. 복잡한 매핑 문서화
Verified# 좋음: 문서화됨
# 모든 속성을 해당 getter 메서드로 변환
# 예: { name: String } => { getName: () => String }
type ToGetters<T> = {
[K in keyof T as `get${Capitalize<K>}`]: () => T[K]
}
4. 조건부 타입과 결합
Verified# 좋음: 스마트 변환
type SmartNullable<T> = {
[K in keyof T]: T[K] extends String | Integer
? T[K] | nil
: T[K]
}
일반적인 패턴
레포지토리 패턴
Verifiedtype Repository<T> = {
find_by_id: (id: Integer) => T | nil,
find_all: () => Array<T>,
save: (entity: T) => T,
update: (id: Integer, data: Partial<T>) => T | nil,
delete: (id: Integer) => Boolean
}
type CRUDHandlers<T> = {
create: (data: Omit<T, "id">) => T,
read: (id: Integer) => T | nil,
update: (id: Integer, data: Partial<T>) => T | nil,
delete: (id: Integer) => Boolean
}
상태 관리
Verifiedtype State<T> = T
type Actions<T> = {
[K in keyof T as `set${Capitalize<K>}`]: (value: T[K]) => void
} & {
[K in keyof T as `get${Capitalize<K>}`]: () => T[K]
}
type Reducers<T> = {
[K in keyof T]: (state: T[K], action: any) => T[K]
}
제한사항
새 속성을 추가할 수 없음
Verified# 원본 타입에 없는 속성을 추가할 수 없음
type Extended<T> = {
[K in keyof T]: T[K]
# new_property: String # 에러: 매핑된 타입에서 새 속성을 추가할 수 없음
}
# 대신 교차 사용
type Extended<T> = T & { new_property: String }
키 타입 제한
Verified# 키는 String | Symbol | Integer여야 함
type ValidKeys = { [K in String]: any } # OK
type InvalidKeys = { [K in User]: any } # 에러: User는 유효한 키 타입이 아님
다음 단계
이제 매핑된 타입을 이해했으니 다음을 탐색하세요: