TypeScript如何移除私有类属性的readonly修饰符?
背景说明
TypeScript 设计上有意限制keyof操作符无法获取类的私有/受保护属性,以此保证私有属性作为类内部实现细节的类型安全。目前没有官方方案可以自动获取包含私有属性在内的所有类成员类型,因此不存在完全不需要手动指定私有属性名的通用Writable实现。
问题1:修复BypassReadonly类型
原生BypassReadonly要求泛型P extends keyof T,但私有属性不在keyof T的返回结果中,天生无法支持私有属性场景,直接优化BypassReadonly2即可,仅在定义处加一次@ts-ignore,使用时完全保留类型检查能力:
type Writable<T> = { -readonly [P in keyof T]: T[P] }; // 仅定义处加一次忽略,完全符合使用要求 type BypassReadonly2<T extends {}, P extends string> = Writable<T> & { // @ts-ignore: 泛型场景下TS禁止索引私有属性,实际使用时传入明确属性名可正常推导类型 -readonly [p in P]: T[p] }
修复后使用完全类型安全:属性名拼写错误、赋值类型不匹配都会正常抛出类型错误,不会丢失检查:
class Test { private readonly privateProp!: string; public readonly publicProp!: string; public test() { // 公开属性正常修改 (this as Writable<this>).publicProp = 'test'; // 私有属性修改完全类型安全 (this as BypassReadonly2<Test, 'privateProp'>).privateProp = 'test'; // 同时修改多个私有属性传联合类型即可 (this as BypassReadonly2<Test, 'privateProp' | 'otherPrivateProp'>).privateProp = 'test'; } }
问题2:更优雅的实现方案
如果是类内部高频修改私有只读属性,可以直接在类内部定义专属可写类型,不需要借助通用泛型工具,写法更简洁:
class Test { private readonly privateProp!: string; public readonly publicProp!: string; // 类内部可直接访问私有属性类型,无需额外泛型 type WritableSelf = Writable<this> & { -readonly privateProp: string // 其他需要修改的私有只读属性统一在这里声明即可 } public test() { (this as WritableSelf).publicProp = 'test'; (this as WritableSelf).privateProp = 'test'; } }
目前没有完全不需要手动指定私有属性名的方案,这个限制是TypeScript类型系统的设计层面决定的,除非官方后续新增相关语法支持,否则没有其他绕过方式。
内容的提问来源于stack exchange,提问作者Maciej Kravchyk
相关产品推荐
相关产品推荐

