TypeScript编程06-映射类型

张开发
2026/4/4 8:25:42 15 分钟阅读
TypeScript编程06-映射类型
TypeScript编程06-映射类型文章目录TypeScript编程06-映射类型第一章基础概念1.1 什么是映射类型第二章PartialT - 可选化2.1 基本用法2.2 实现原理第三章RequiredT - 必選化3.1 基本用法3.2 实现原理第四章ReadonlyT - 只读化4.1 基本用法4.2 浅只读 vs 深只读第五章PickT, K - 属性挑选5.1 基本用法5.2 实现原理第六章OmitT, K - 属性排除6.1 基本用法6.2 与 Pick 的关系第七章RecordK, T - 键值映射7.1 基本用法7.2 与索引签名的区别第八章组合应用与实战8.1 如何组合使用这些映射类型8.2 自定义映射类型第九章常见问题与陷阱9.1 可选属性与 undefined 的区别9.2 映射类型对方法的影响9.3 keyof 与联合类型的顺序第十章速查表第一章基础概念1.1 什么是映射类型Q什么是 TypeScript 中的映射类型A映射类型Mapped Types是 TypeScript 提供的基于旧类型创建新类型的工具它会遍历目标类型的每个属性并应用特定的转换规则。本质上是一种类型层面的批量操作工具。// 基础语法结构typeNewType{[KinkeyofOldType]:NewValueType}第二章PartialT - 可选化2.1 基本用法QPartialT的作用是什么A将类型T的所有属性变为可选?。常用于函数参数、表单更新等场景。interfaceUser{name:string;age:number;email:string;}typePartialUserPartialUser;// 等价于// {// name?: string;// age?: number;// email?: string;// }// 实际应用更新用户信息functionupdateUser(user:User,updates:PartialUser):User{return{...user,...updates};}constuser{name:张三,age:25,email:zhangexample.com};updateUser(user,{age:26});// ✅ 只需传入想更新的字段2.2 实现原理QPartialT是如何实现的AtypePartialT{[PinkeyofT]?:T[P];};关键点keyof T获取T的所有键组成的联合类型P in ...遍历每个键?:将属性标记为可选第三章RequiredT - 必選化3.1 基本用法QRequiredT的作用是什么A将类型T的所有属性变为必选移除?。与PartialT作用相反。interfaceConfig{host?:string;port?:number;ssl?:boolean;}typeRequiredConfigRequiredConfig;// 等价于// {// host: string;// port: number;// ssl: boolean;// }// 实际应用确保配置完整functioncreateServer(config:RequiredConfig){// 此时 config 的所有属性都一定有值console.log(config.host,config.port,config.ssl);}3.2 实现原理QRequiredT是如何实现的AtypeRequiredT{[PinkeyofT]-?:T[P];};关键点-?移除可选修饰符-表示移除?表示可选第四章ReadonlyT - 只读化4.1 基本用法QReadonlyT的作用是什么A将类型T的所有属性变为只读readonly防止属性被重新赋值。interfacePoint{x:number;y:number;}typeReadonlyPointReadonlyPoint;// 等价于// {// readonly x: number;// readonly y: number;// }constpoint:ReadonlyPoint{x:10,y:20};point.x5;// ❌ 报错无法为只读属性赋值4.2 浅只读 vs 深只读QReadonlyT是深只读吗A不是它是浅只读Shallow Readonly只影响第一层属性。interfaceUser{info:{name:string;age:number};}constuser:ReadonlyUser{info:{name:张三,age:25}};// user.info { name: 李四, age: 30 }; // ❌ 报错不能修改 info 本身user.info.name李四;// ✅ 不报错可以修改嵌套对象的属性// 深只读实现typeDeepReadonlyT{readonly[PinkeyofT]:T[P]extendsobject?DeepReadonlyT[P]:T[P];};constdeepUser:DeepReadonlyUser{info:{name:张三,age:25}};// deepUser.info.name 李四; // ❌ 报错深层属性也是只读的第五章PickT, K - 属性挑选5.1 基本用法QPickT, K的作用是什么A从类型T中挑选出一组属性K来构造新类型。interfaceUser{id:number;name:string;email:string;password:string;createdAt:Date;}// 只选择 id 和 nametypeUserPreviewPickUser,id|name;// 等价于// {// id: number;// name: string;// }// 实际应用API 返回精简数据functiongetUserPreview(id:number):PromiseUserPreview{returnfetch(/api/users/${id}/preview).then(rr.json());}5.2 实现原理QPickT, K是如何实现的AtypePickT,KextendskeyofT{[PinK]:T[P];};关键点K extends keyof T约束K必须是T的键的子集遍历K而非keyof T实现选择性提取第六章OmitT, K - 属性排除6.1 基本用法QOmitT, K的作用是什么A从类型T中排除一组属性K来构造新类型。与PickT, K相反。interfaceUser{id:number;name:string;email:string;password:string;createdAt:Date;}// 排除敏感字段 password 和 createdAttypePublicUserOmitUser,password|createdAt;// 等价于// {// id: number;// name: string;// email: string;// }// 实际应用API 返回公开数据functionsanitizeUser(user:User):PublicUser{const{password,createdAt,...publicInfo}user;returnpublicInfo;}6.2 与 Pick 的关系QOmit和Pick可以互相转换吗A可以它们是互补的// Omit 可以用 Pick Exclude 实现typeOmitT,KextendskeyofanyPickT,ExcludekeyofT,K;// 示例验证typeAOmitUser,password;typeBPickUser,id|name|email|createdAt;// A 和 B 是等价的第七章RecordK, T - 键值映射7.1 基本用法QRecordK, T的作用是什么A构造一个对象类型其键的类型为K值的类型为T。常用于创建字典、映射表。// 键为字符串值为数字typePageNameshome|about|contact;typePageInfoRecordPageNames,{title:string;path:string};constpages:PageInfo{home:{title:首页,path:/},about:{title:关于,path:/about},contact:{title:联系,path:/contact}// 不能添加其他键也不能缺少任何键};7.2 与索引签名的区别QRecordK, T和索引签名有什么区别A特性RecordK, T索引签名键的范围有限的联合类型无限的类型如string必须包含所有键✅ 是❌ 否适用场景固定键集合动态键集合// Record键是有限的typeStatuspending|success|error;conststatusMap:RecordStatus,string{pending:处理中,success:成功,error:失败// 不能少也不能多};// 索引签名键是无限的interfaceDictionary{[key:string]:number;}constdict:Dictionary{a:1,b:2,// 可以有任意多个键};第八章组合应用与实战8.1 如何组合使用这些映射类型Q实际开发中如何组合使用这些工具类型A可以链式组合解决复杂类型问题interfaceProduct{id:number;name:string;price:number;stock:number;description:string;createdAt:Date;updatedAt:Date;}// 场景创建产品时只需要部分字段且都是可选的typeCreateProductDTOPartialPickProduct,name|price|description|stock;// 场景更新产品时id 必选其他可选typeUpdateProductDTOPartialOmitProduct,id|createdAt|updatedAtPickProduct,id;// 场景前端展示用的产品信息排除敏感字段且只读typeProductViewReadonlyOmitProduct,stock|updatedAt;// 场景按状态分组的产品列表typeProductStatusavailable|outOfStock|discontinued;typeProductsByStatusRecordProductStatus,Product[];8.2 自定义映射类型Q如何基于这些工具类型创建自定义映射类型A可以扩展或组合内置工具类型// 1. 可空类型值可以是 nulltypeNullableT{[PinkeyofT]:T[P]|null;};// 2. 可选且只读typeReadonlyPartialTReadonlyPartialT;// 3. 深部分递归处理嵌套对象typeDeepPartialT{[PinkeyofT]?:T[P]extendsobject?DeepPartialT[P]:T[P];};// 4. 提取函数参数类型typeParametersTextends(...args:any[])anyTextends(...args:inferP)any?P:never;// 5. 提取函数返回值类型typeReturnTypeTextends(...args:any[])anyTextends(...args:any[])inferR?R:any;第九章常见问题与陷阱9.1 可选属性与 undefined 的区别QPartialT和将属性设为undefined有什么区别AinterfaceA{x?:string;// 可选属性可以不存在y:string|undefined;// 必选但可为 undefined必须存在值可以是 undefined}consta1:A{};// ❌ 缺少 yconsta2:A{y:undefined};// ✅ y 必须存在即使值是 undefined9.2 映射类型对方法的影响QReadonlyT会影响类的方法吗A会但不会阻止方法内部修改状态classCounter{count0;increment(){this.count;// 内部可以修改}}constreadonlyCounter:ReadonlyCounternewCounter();// readonlyCounter.count 5; // ❌ 报错readonlyCounter.increment();// ✅ 允许调用内部修改了 count9.3 keyof 与联合类型的顺序QPick和Omit的第二个参数顺序重要吗A不重要联合类型是无序的typeAPickUser,id|name;typeBPickUser,name|id;// A 和 B 完全相同第十章速查表工具类型作用记忆口诀PartialT所有属性可选Partial Partial部分的RequiredT所有属性必选Required Required必需的ReadonlyT所有属性只读Readonly Read只读PickT, K挑选指定属性Pick Pick挑选OmitT, K排除指定属性Omit Omit省略RecordK, T创建键值映射Record Record记录/字典

更多文章