元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
TypeScript环境准备
安装与配置
第一个TS程序
编译流程解析
▶
基础类型系统
类型注解语法
原始类型定义
数组与元组
接口与对象
▶
高级类型系统
泛型编程
条件类型
映射类型
类型推断
类型保护
高级类型工具
▶
函数开发
函数类型声明
可选参数与默认值
箭头函数应用
函数重载
泛型函数
▶
类与面向对象
类的定义
继承与修饰符
存取器使用
抽象类与接口
泛型类与抽象类
访问修饰符与属性
▶
模块化开发
模块导入导出
类型声明文件
命名空间
模块解析策略
▶
工程实践
tsconfig详解
常见编译选项
项目构建配置
代码组织最佳实践
单元测试
调试技巧
▶
常见问题
类型错误处理
类型断言技巧
类型兼容性
版本迁移指南
发布时间:
2025-03-31 09:39
↑
☰
# 映射类型 映射类型是TypeScript中一个强大的类型工具,它允许我们基于已有的类型创建新的类型。本文将详细介绍映射类型的使用方法和应用场景。 ## 基础映射类型 最基本的映射类型是将一个类型的所有属性转换为新的类型: ```typescript type Readonly<T> = { readonly [P in keyof T]: T[P]; }; interface Person { name: string; age: number; } type ReadonlyPerson = Readonly<Person>; // 等价于: // { // readonly name: string; // readonly age: number; // } ``` ## 映射类型修饰符 ### 1. readonly修饰符 ```typescript // 添加readonly type Readonly<T> = { readonly [P in keyof T]: T[P]; }; // 移除readonly type Mutable<T> = { -readonly [P in keyof T]: T[P]; }; ``` ### 2. 可选修饰符 ```typescript // 添加可选修饰符 type Partial<T> = { [P in keyof T]?: T[P]; }; // 移除可选修饰符 type Required<T> = { [P in keyof T]-?: T[P]; }; ``` ## 键名重映射 TypeScript 4.1引入了键名重映射功能,允许我们在映射过程中转换属性名: ```typescript type Getters<T> = { [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P]; }; interface Person { name: string; age: number; } type PersonGetters = Getters<Person>; // 等价于: // { // getName: () => string; // getAge: () => number; // } ``` ## 条件类型与映射类型结合 我们可以在映射类型中使用条件类型来创建更复杂的类型转换: ```typescript type PickByValueType<T, ValueType> = { [P in keyof T as T[P] extends ValueType ? P : never]: T[P]; }; interface Person { name: string; age: number; address: string; isActive: boolean; } type StringProps = PickByValueType<Person, string>; // 等价于: // { // name: string; // address: string; // } ``` ## 实际应用场景 ### 1. 创建不可变对象 ```typescript type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]; }; interface Config { api: { endpoint: string; timeout: number; }; debug: boolean; } type ReadonlyConfig = DeepReadonly<Config>; ``` ### 2. 表单验证 ```typescript type ValidationRules<T> = { [P in keyof T]: { required?: boolean; min?: number; max?: number; pattern?: RegExp; validate?: (value: T[P]) => boolean; }; }; interface UserForm { username: string; age: number; email: string; } const userValidation: ValidationRules<UserForm> = { username: { required: true, min: 3, max: 20 }, age: { required: true, min: 18 }, email: { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ } }; ``` ### 3. API请求状态管理 ```typescript type AsyncState<T> = { [P in keyof T]: { data: T[P] | null; loading: boolean; error: Error | null; }; }; interface UserData { profile: { name: string; email: string; }; posts: string[]; } type UserDataState = AsyncState<UserData>; // 等价于: // { // profile: { // data: { name: string; email: string; } | null; // loading: boolean; // error: Error | null; // }; // posts: { // data: string[] | null; // loading: boolean; // error: Error | null; // }; // } ``` ## 最佳实践 1. **保持类型简单**:虽然映射类型很强大,但过于复杂的类型可能难以维护和理解。 2. **合理使用泛型约束**:在需要限制映射类型的输入范围时,使用泛型约束: ```typescript type StringKeys<T> = { [P in keyof T as T[P] extends string ? P : never]: T[P]; }; ``` 3. **使用类型别名**:对于复杂的映射类型,使用类型别名来提高可读性: ```typescript type PropertyType<T, K extends keyof T> = T[K]; type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>; ``` ## 常见工具类型 1. **Record**:创建具有指定键类型和值类型的对象类型 ```typescript type Record<K extends keyof any, T> = { [P in K]: T; }; ``` 2. **Pick**:从类型中选择指定的属性 ```typescript type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; ``` 3. **Omit**:从类型中排除指定的属性 ```typescript type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>; ``` ## 总结 映射类型是TypeScript中一个强大的类型系统特性,它允许我们: - 基于现有类型创建新的类型 - 修改属性的修饰符(readonly, 可选等) - 重命名属性 - 结合条件类型创建复杂的类型转换 合理使用映射类型可以帮助我们编写更加类型安全和可维护的代码。但要注意避免创建过于复杂的类型,保持代码的可读性和可维护性。在实际开发中,应该根据具体需求选择合适的映射类型方案。