在TypeScript中,类型映射(Mapped Types)是一种强大的类型转换工具,它允许我们从旧的类型生成新的类型。本文将介绍类型映射的不同方式和分类,每种映射方法的使用场景,以及详细的示例代码。
基础映射类型
基础映射类型是最简单的映射类型,它通过遍历一个已知的联合类型来创建新类型。
使用场景: 当你需要根据一个联合类型的值来创建对象类型时,基础映射类型非常有用。
// 基础映射类型示例
type Permissions = 'read' | 'write' | 'delete';
type AccessControl = { [K in Permissions]: boolean };
// AccessControl类型等同于:
// {
// read: boolean;
// write: boolean;
// delete: boolean;
// }
条件映射类型
条件映射类型使用条件类型(Conditional Types)来决定如何映射到新的属性类型。
使用场景: 当你需要根据属性的键或现有类型来决定新属性的类型时,条件映射类型非常有用。
// 条件映射类型示例
type Options = 'option1' | 'option2' | 'option3';
type OptionFlags = { [K in Options]: K extends 'option2' ? string : number };
// OptionFlags类型等同于:
// {
// option1: number;
// option2: string;
// option3: number;
// }
通过模板字面量进行映射
模板字面量类型(Template Literal Types)可以与映射类型结合,创建基于字符串模式的类型。
使用场景: 当你需要创建与字符串模式匹配的属性名时,模板字面量映射类型非常有用。
// 模板字面量映射类型示例
type EventNames = 'onClick' | 'onHover' | 'onFocus';
type EventHandlers = { [K in `handle${EventNames}`]: () => void };
// EventHandlers类型等同于:
// {
// handleonClick: () => void;
// handleonHover: () => void;
// handleonFocus: () => void;
// }
使用泛型进行映射
泛型可以与映射类型结合,允许我们创建更通用和可重用的映射类型。
使用场景: 当你需要创建可适用于多种类型的映射类型时,泛型映射类型非常有用。
// 使用泛型进行映射示例
type NullableProperties<T> = { [P in keyof T]: T[P] | null };
// 使用NullableProperties将所有属性变为可空类型
interface User {
id: number;
name: string;
}
type NullableUser = NullableProperties<User>;
// NullableUser类型等同于:
// {
// id: number | null;
// name: string | null;
// }
映射修饰符
映射类型支持使用修饰符来调整属性的可选性和只读性。
使用场景: 当你需要创建属性的只读版本或可选版本时,映射修饰符非常有用。
// 映射修饰符示例
type Readonly<T> = { readonly [P in keyof T]: T[P] };
type Optional<T> = { [P in keyof T]?: T[P] };
interface Task {
title: string;
completed: boolean;
}
type ReadonlyTask = Readonly<Task>;
type OptionalTask = Optional<Task>;
// ReadonlyTask类型等同于:
// {
// readonly title: string;
// readonly completed: boolean;
// }
// OptionalTask类型等同于:
// {
// title?: string;
// completed?: boolean;
// }
键名重映射
在TypeScript 4.1及以上版本中,类型映射得到了进一步的增强,允许我们通过使用as
语法来重新映射键名。这意味着我们可以在创建新类型时改变属性的名称。
使用场景: 当你需要在新的类型中使用不同的属性名时,键名重映射非常有用。
// 键名重映射示例
type MappedTypeWithNewKeys<T> = {
[K in keyof T as NewKeyType]: T[K]
}
// 示例:将对象中的键名转换为大写
type Options = {
firstOption: boolean;
secondOption: boolean;
};
type CapitalizedOptions = {
[K in keyof Options as Capitalize<K>]: Options[K]
}
// CapitalizedOptions类型等同于:
// {
// FirstOption: boolean;
// SecondOption: boolean;
// }
在上面的示例中,我们使用了Capitalize
工具类型,它是TypeScript内置的一个条件类型,用于将字符串字面量类型的首字母转换为大写。
进阶应用:我们还可以结合条件类型来有选择性地重映射键名,或者使用模板字面量类型来创建更复杂的键名模式。
// 有选择性地重映射键名
type User = {
id: number;
firstName: string;
lastName: string;
isAdmin: boolean;
};
type UserWithoutSensitiveInfo = {
[K in keyof User as Exclude<K, 'isAdmin'>]: User[K]
}
// UserWithoutSensitiveInfo类型等同于:
// {
// id: number;
// firstName: string;
// lastName: string;
// }
// 使用模板字面量类型重映射键名
type PrefixedUser = {
[K in keyof User as `user_${K}`]: User[K]
}
// PrefixedUser类型等同于:
// {
// user_id: number;
// user_firstName: string;
// user_lastName: string;
// user_isAdmin: boolean;
// }
通过键名重映射,我们可以创建出更加灵活和丰富的类型定义,这对于处理复杂的数据结构和类型转换非常有帮助。