前言
我们都知道 TS 的内置工具类型 Readonly 能够给一个对象的所有属性都加上 readonly 关键字,那么我们要是想要给一个对象的某一些字段加上这个关键字,应该要怎么操作,最近碰到了这个需求,今天用一篇文章记录一下。
在这之前,我们要来理解一个概念,就是 TS 中的 & 和 | 分别代表什么 ,如果想直接看工具类型的可以跳到文章最后
& 交集
在数学上面的交集,我们理解为两个集合公共拥有的部分,比方说我现在有两个集合 [1,2,3] 和 [2,3,4] 那么他们的交集应该是 [2,3] 这个交集可以理解为两个集合都拥有的部分。
那么在 TS 当中,假如是两个 基本类型 之间使用这个符号,比如说
type AAA = number & string
很明显,他并不可能存在,因为不存在一个属性,他又是 字符串,又是 数字。
但是用在对象类型上的时候就有着不一样的现象:
type OOO = {a:1} & {b:2}
根据上面的理解,我们可以认为是一个对象,它既要是 {a:1} 又要是 {b:2} 那么他能怎么办,是不是就只能同时包含两个人共有的属性。
| 并集
在数学上面的并集,我们理解为由所有属于A或属于B的元素组成的集合,比方说我现在有两个集合 [1,2,3] 和 [2,3,4] 那么他们的交集应该是 [1,,2,3,4] 这个并集可以理解为两个集合拥有的部分的合并。
那么在 TS 当中,假如是两个 基本类型 之间使用这个符号,比如说
type AAA = number & string
这就是我们常说的联合类型,代表这个属性既可以是 字符串,又可以是 数字
但是用在对象类型上的时候就有着不一样的现象:
type OOO = {a:1} | {b:2}
根据上面的理解,我们可以认为是一个对象,它既可以是 {a:1} 又可以是 {b:2} 那么他就会变成两个对象都含有的属性,很明显两个对象都含有的属性为空,这里我们拿一个其他例子可以更好地理解一下。
type OOO = {a:1, b:3} | {b:2}
启发:
一个全是 readonly 修饰语的对象类型 一旦 &并 上另一个对象类型,并且另一个对象类型中有同样的字段,但是并没有使用 readonly 修饰符,那么生产的新对象,这个 readonly 修饰符会消失,
那么可以根据这个特性,我们在为一个对象的指定 key 添加 readonly 修饰符
通过先将这个对象的所有词条都变成 readonly 然后并上另一个 除了需要的 key 以外的 key 都含有的对象,就能够实现
实现
根据上面的思路,我们可以列出几点需要的操作,
-
需要获取需求对象中,除了需要的key以外的key组成的新对象
-
需要将原有对象全部加上 readonly 修饰符
我们就假设一个新的泛型类型 AddReadonly 他的第一个参数为目标对象,第二个参数是一个字符串联合类型,字符串就是我们需要添加 readonly 的key
然后从第一步开始,我们能够发现,第一步有点像一个内置类型 Omit 的定义,从一个对象当中剔除某些属性,那么我们是不是就可以利用这个内置类型来剔除 里面的所有的 然后得到一个新的类型
type SSS = {
a:1,
b:2,
c:3
}
type SSSS = Omit<SSS, 'a' | 's'>
// type SSSS = {
// b: 2;
// c: 3;
// }
第二步,我们还是可以通过 TS 的内置 Readonly 类型,来将 中的所有属性都加上 Readonly 修饰符。
type SSS = {
a:1,
b:2,
c:3
}
type SSSS = Readonly<SSS>
// type SSSS = {
// readonly a:1,
// readonly b: 2;
// readonly c: 3;
// }
然后剩下的就简单了,根据分析所说只需要取两个对象的交集,就是我们最后所需要的结果,结合一下两个内置类型,新建一个 AddReadonly 类型
type AddReadonly<T extends object, U extends string> = Readonly<T> & Omit<T,U>
type A1 = {
b: number,
c: number
}
type E1 = AddReadonly<A1, 'b' | 's'>
type E2 = {[P in keyof E1]: E1[P]}