TypeScript中的类型映射(Mapping Types):探索类型迭代的无限可能

在TypeScript的世界里,类型不仅仅是静态的声明,它们也可以是动态的、可迭代的。通过TypeScript的映射类型(Mapping Types)特性,我们可以利用 in关键字结合联合类型或索引签名,对已有的类型进行迭代和转换,从而创建出全新的类型定义。这一特性极大地增强了TypeScript在复杂数据结构处理中的灵活性和表达能力。

一、什么是映射类型?

映射类型是一种高级类型操作,它允许我们根据一个已存在的类型(称为“源类型”),通过某种规则(称为“映射规则”)来生成一个新的类型。这种操作类似于数组中的map函数,但作用于类型层面,而非值层面。

二、如何使用in关键字进行类型迭代?

在映射类型中,in关键字扮演着核心角色。它允许我们遍历源类型的所有键(key),并对每个键应用一个转换规则,从而生成目标类型中的新属性。这种机制为处理对象类型或接口中的属性提供了极大的便利。

三、示例:转换对象属性的类型

假设我们有一个表示用户信息的接口,我们希望将接口中所有属性的类型从string转换为number(尽管这在现实中可能不常见,但仅作为示例)。

interface UserInfo {  
  id: string;  
  name: string;  
  age: string; // 假设这里年龄也被错误地声明为string  
}  
  
// 使用映射类型将UserInfo中所有string类型的属性转换为number类型  
type NumberUserInfo = {  
  [K in keyof UserInfo as `${K}Number`]: number;  
};  
  
// 注意:这里使用了`as`语法进行键名重命名,并假设我们需要创建新属性名而非直接覆盖原属性类型  
// 如果你只是想转换类型而不改变键名,可以省略`as`部分并直接在类型位置指定number  
  
// 更接近实际用途的版本,不改变键名:  
type ConvertedUserInfo = {  
  [K in keyof UserInfo]: number;  
};  
  
// 但请注意,直接这样转换可能不符合逻辑,因为id和name通常不是数字  
// 这里只是为了演示映射类型的使用

根据上一篇我们学习《TS进阶之泛型分发》一起来思考泛型映射类型应该怎么做到递归?

比如说:

interface IInfo {
  name: string;
  age: number;
  school: {
    middleSchool: string;
    highSchool: string;
    university: string;
  }
}

type OptionalInfo = Partial<IInfo>;

可以看到利用 Partial 关键字仅仅对于对象类型中的最外层进行了可选标记。如下图1-1所示

 图1-1

但是对于内层嵌套类型比如 school 仍是一个对象类型,那么此时是无法深度进入 school 类型中进行标记的。

那么假如此时我有需求希望实现深度可选,应该如何做呢?大家可以查看 《TS进阶之泛型分发》提到过的条件判断和循环结合来考虑下。

interface IInfo {
  name: string;
  age: number;
  school: {
    middleSchool: string;
    highSchool: string;
    university: string;
  };
}

// 其实实现很简单,首先我们在构造新的类型value时
// 利用 extends 条件判断新的类型value是否为 object 
// 如果是 -> 那么我仍然利用 deepPartial<T[K]> 进行包裹递归可选处理
// 如果不是 -> 普通类型直接返回即可
type deepPartial<T> = {
  [K in keyof T]?: T[K] extends object ? deepPartial<T[K]> : T[K];
};

type OptionalInfo = deepPartial<IInfo>;

let value: OptionalInfo = {
  name: '1',
  school: {
    middleSchool:'xian'
  },
};
 四、映射类型的优势
  1. 提高代码复用性:通过映射类型,我们可以避免为每种类型转换场景编写独立的类型定义,减少了代码冗余。
  2. 增强类型安全性:TypeScript的编译器会在编译时检查映射类型的正确性,确保类型安全。
  3. 促进代码可维护性:当源类型发生变化时,映射类型会自动适应这些变化,减少了因类型不匹配而导致的错误。
五、实际应用场景
  • 在使用Redux、Vuex等状态管理库时,定义action types和state shapes。
  • 在构建复杂的数据结构时,如嵌套对象、联合类型等,通过映射类型简化类型定义。
  • 在实现泛型库或框架时,提供灵活的类型转换功能。
六、结论

TypeScript的映射类型是一项强大的特性,它允许我们通过迭代和转换已有类型来创建新的类型定义。通过in关键字的使用,我们可以轻松地遍历源类型的所有属性,并应用自定义的转换规则。掌握映射类型的使用,将使你在TypeScript项目中更加游刃有余地处理复杂的数据结构和类型需求。

继续下一章《TypeScript中的逆变与协变:深入理解与应用》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鎈卟誃筅甡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值