映射类型可以从旧类型创建新类型,通过遍历类型的属性来转换类型。映射类型是 TypeScript 中强大的类型转换工具。
映射类型使用 in 关键字遍历类型的属性。
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
interface User {
id: number
name: string
}
type ReadonlyUser = Readonly<User>
const user: ReadonlyUser = {
id: 1,
name: "张三"
}
[P in keyof T] 遍历 T 的所有属性,readonly 修饰符使属性只读。
TypeScript 提供了一些内置的映射类型。
interface User {
id: number
name: string
email: string
}
type PartialUser = Partial<User>
type RequiredUser = Required<User>
type ReadonlyUser = Readonly<User>
type UserKeys = keyof User
type UserPick = Pick<User, "id" | "name">
type UserOmit = Omit<User, "email">
type UserRecord = Record<"a" | "b", User>
const partialUser: PartialUser = { name: "张三" }
const readonlyUser: ReadonlyUser = { id: 1, name: "张三", email: "test@example.com" }
const pickedUser: UserPick = { id: 1, name: "张三" }
const omittedUser: UserOmit = { id: 1, name: "张三" }
Partial<T>:所有属性变为可选Required<T>:所有属性变为必需Readonly<T>:所有属性变为只读Pick<T, K>:选择指定的属性Omit<T, K>:排除指定的属性Record<K, T>:创建键为 K、值为 T 的类型可以使用 + 和 - 添加或移除修饰符。
interface User {
readonly id: number
name?: string
}
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
type RequiredUser<T> = {
[P in keyof T]-?: T[P]
}
type MutableUser = Mutable<User>
type RequiredUserType = RequiredUser<User>
const mutableUser: MutableUser = {
id: 1,
name: "张三"
}
mutableUser.id = 2
-readonly 移除只读修饰符,-? 移除可选修饰符。
可以创建自定义的映射类型。
type Nullable<T> = {
[P in keyof T]: T[P] | null
}
interface User {
id: number
name: string
}
type NullableUser = Nullable<User>
const user: NullableUser = {
id: 1,
name: null
}
Nullable<T> 将所有属性类型变为可空。
映射类型可以与条件类型结合使用。
type NonNullableProperties<T> = {
[P in keyof T]: NonNullable<T[P]>
}
interface User {
id: number | null
name: string | null
email: string
}
type NonNullableUser = NonNullableProperties<User>
const user: NonNullableUser = {
id: 1,
name: "张三",
email: "test@example.com"
}
NonNullableProperties<T> 将所有属性的非空类型提取出来。
TypeScript 4.1 引入了键重映射,使用 as 子句。
type Getters<T> = {
[P in keyof T as `get${Capitalize<string & P>}`]: () => T[P]
}
interface User {
id: number
name: string
}
type UserGetters = Getters<User>
const getters: UserGetters = {
getId: () => 1,
getName: () => "张三"
}
as 子句可以重命名键,Capitalize 是内置的字符串操作类型。
键重映射可以过滤属性。
type OnlyString<T> = {
[P in keyof T as T[P] extends string ? P : never]: T[P]
}
interface User {
id: number
name: string
email: string
age: number
}
type StringProperties = OnlyString<User>
const strings: StringProperties = {
name: "张三",
email: "test@example.com"
}
never 类型会从联合类型中排除,实现属性过滤。
映射类型在实际开发中常用于创建表单类型。
interface Entity {
id: number
name: string
email: string
createdAt: Date
}
type Form<T> = {
[P in keyof T]?: T[P] | string
}
type EntityForm = Form<Entity>
const form: EntityForm = {
id: "1",
name: "张三",
email: "test@example.com"
}
function validateForm<T>(form: Form<T>): Partial<T> {
return Object.entries(form).reduce((acc, [key, value]) => {
if (value !== undefined) {
acc[key as keyof T] = value as T[keyof T]
}
return acc
}, {} as Partial<T>)
}
Form<T> 将所有属性变为可选,并允许字符串值,适用于表单处理。
映射类型从旧类型创建新类型,通过遍历属性来转换类型。TypeScript 提供了 Partial、Required、Readonly、Pick、Omit、Record 等内置映射类型。可以使用 + 和 - 添加或移除修饰符。键重映射可以重命名和过滤属性。映射类型在实际开发中常用于创建表单类型和数据转换类型。