一,前言
本篇介绍TS的另一个高级类型-映射类型
二,映射类型
映射类型:
TS允许将一个类型映射成另外一个类型
将一个接口的所有属性映射为只读:
// 定义接口Obj
interface Obj {
a: number
b: string
c: boolean
}
// 使用类型别名定义类型ReadonlyObj
type ReadonlyObj = Readonly<Obj> // Readonly是TS内置的泛型接口
ReadonlyObj与Obj成员完全相同,区别是ReadonlyObj中的成员属性均为只读
三,映射类型的实现原理
TS的内置类库
刚刚说了,Readonly是TS内置的泛型接口,查看TS源码(TS内置的类库)
node_module/typescript/lib/lib.es5.d.ts:
Readonly的实现原理:
从源码可以看出Readonly是一个可索引类型的泛型接口
1)索引签名为P in keyof T :
其中keyof T就是一个一个索引类型的查询操作符,表示类型T所有属性的联合类型
2)P in :
相当于执行了一个for in操作,会把变量P依次绑定到T的所有属性上
3)索引签名的返回值就是一个索引访问操作符 : T[P] 这里代表属性P所指定的类型
4)最后再加上Readonly就把所有的属性变成了只读,这就是Readonly的实现原理
TS还预置了很多其他的映射类型:
如:将一个接口的所有属性变成可选的Partial映射类型
type PartialObj = Partial<Obj> // 可选
源码:
可以发现:
可选和只读映射类型的实现几乎一样,知识属性变为可选
可以抽取对象子集的Pick映射类型:
type PickObj = Pick<Obj, 'a' | 'b'> // 抽取接口Obj中的属性a和b,形成新类型
新类型中仅包含指定属性a和b:
源码:
/**
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
Pick映射类型的实现原理:
Pick映射类型有两个参数:
第一个参数T,表示要抽取的目标对象
第二个参数K,具有一个约束:K一定要来自T所有属性字面量的联合类型,
即映射得到的新类型的属性一定要从K中选取
以上三种映射类型官方称为同态,意思是只作用于obj属性而不会引入新的属性
会引入新属性的非同态映射类型
会创建新属性的映射类型Record
type RecordObj = Record<'x' | 'y', Obj>
第一个参数是预定义的新属性,比如x,y
第二个参数就是已知类型
映射出的新类型所具有的属性由Record的第一个属性指定
而这些属性类型为第二个参数指定的已知类型
这种类型就是一个非同态的类型
Record映射类型源码:
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
映射类型本质上是一种预先定义的泛型接口,
通常还会结合索引类型,获取对象的属性和属性值,
从而将一个对象映射为我们想要的结构,即目标类型
四,结尾
本篇介绍了TS的又一种高级类型-映射类型
通过Readonly(只读),Partial(可选),Pick(抽取),三个同态映射类型
和非同态映射类型Record(录制)介绍了映射类型使用和实现原理
在TS的内置类库中还有更多映射类型,可以去尝试