TypeScript 映射类型怎么写
你有没有过这种情况?写代码时明明要复用一段逻辑,结果只能把相同的类型定义抄3遍,改一个地方就顾此失彼,最后搞出一堆冗余代码?要是你用了TypeScript,映射类型就能解决这个麻烦。它就像个“类型复印机”,能快速从旧类型变出符合需求的新类型,今天就用大家日常会碰到的场景,把它讲得明明白白。
先搞懂:映射类型到底是啥
映射类型的核心逻辑,说穿了就是“遍历旧类型的属性,挨个加工后生成新类型”。举个生活化的例子:你有一张记录朋友信息的表格,旧类型就像这张表,有“姓名”“年龄”“电话”这些列;映射类型就是按你要的规则,把每一列都改一遍,比如把所有列的内容改成“可选”,或者把所有属性的类型都换成字符串。

简单说,它的公式就是{ [属性名 in 旧属性]: 新类型 },看起来有点像循环,其实就是按旧属性挨个生成新属性,比手动写要高效得多。
最常用的场景:把属性变成“可选”或“只读”
日常开发里,这两个需求最常见——比如写配置项时,很多参数可能不是必填;要保证数据不能被随便修改,就得设成只读。这两个映射类型TypeScript已经帮你做好了,不用自己写,用起来超简单。
比如你有个用户信息的类型:
`typescript
interface User {
name: string;
age: number;
address: string;
}
`
要是想做一个“编辑用户的表单类型”,不用所有字段都填,就用Partial<User>,它就是把User的所有属性都变成可选的,等价于你自己写的:
`typescript
type PartialUser = {
name?: string;
age?: number;
address?: string;
}
`
再比如要保证某个类型的数据不能被修改,像存到本地缓存的配置,就用Readonly<User>,所有属性都变成只读,你改user.name就会报错,避免不小心改坏数据。
进阶用法:自己定义映射规则
要是官方的映射类型满足不了需求,比如要把所有属性的类型都统一成新类型,或者把属性名的前缀改一下,就得自己写映射类型了。
举个例子,你有个获取用户接口的旧类型,返回的字段都是data开头的,比如dataName、dataAge,你想把这些字段去掉data前缀,变成name、age,怎么写?
`typescript
type RemoveDataPrefix<T> = {
[Key in keyof T as Key extends data${infer Rest} ? Rest : Key]: T[Key]
}
`
这里keyof T就是拿到旧类型的所有属性名,as是重命名属性的规则,用了“字符串提取”的技巧:如果属性名是data开头,就把data去掉,剩下的作为新属性名;如果不是,就保留原来的名字。用这个类型处理上面的User,就自动生成你要的新类型,不用手动改每个属性名。
再举个更实用的场景:你写了个产品列表的类型,每个属性都是字符串,现在要做个导出的功能,把所有属性都转成数字(比如导出的表格里年龄是数字格式),映射类型就能批量改类型:
`typescript
type ConvertToNumber<T> = {
[Key in keyof T]: number
}
`
这样不管旧类型有多少属性,新类型的所有属性都是数字,比一个个改省太多事。
别踩这些容易错的小坑
映射类型虽然好用,但新手容易踩两个小坑:一是别乱加多余的属性,比如你写映射时不小心多了个属性,结果新类型多了个不存在的字段,编译也不报错,运行时就会出bug;二是keyof的用法要注意,要是旧类型是联合类型,keyof会把它拆成单个属性,循环时容易出问题,这时候加个泛型约束就能解决。
总的来说,映射类型就是TypeScript给开发者的“类型工具”,不用再重复造轮子,也不用手写一堆重复的类型定义。下次碰到需要批量处理类型的情况,就试试这个“类型复印机”,能少写不少冗余代码,还能减少出错的概率。