TypeScript 实现抽象类时仅删单个getter/setter为何无编译报错
TypeScript抽象类访问器实现校验规则说明
首先看你给出的示例代码:
abstract class P<T> { abstract method(): T; abstract get poke(): string; abstract set poke(p: string); } class C extends P<string> { _p: string = 'p'; method() { return '5'; } // 同时注释getter和setter会触发编译错误,但仅注释一个不会 get poke(): string { return this._p; } set poke(p: string) { this._p = p; } }
你观察到的“同时注释两者才报错”逻辑很直接:此时子类完全不存在poke这个成员,自然不满足抽象类的成员存在性要求,直接触发编译错误。而仅注释其中一个不报错的现象,是TypeScript的刻意设计,核心原因有以下几点:
- 结构化类型系统的核心特性
TypeScript采用结构化类型系统,而非名义类型系统。抽象类中同时声明get poke()和set poke(),本质是约定了poke是一个可读可写的string类型成员,它并不强制要求子类必须用访问器实现,也不强制要求必须同时有get和set:- 你甚至可以直接用普通类属性实现
public poke: string = 'p',完全可以通过校验,因为普通属性天然满足可读可写的要求。 - 仅注释掉get或者set时,子类仍然存在
poke这个同名成员,只要该成员的读写类型和抽象类的约定兼容,就不会触发错误。
- 你甚至可以直接用普通类属性实现
- 兼容JavaScript原生语义
JavaScript本身就支持仅定义getter或者仅定义setter的合法用法:- 仅定义getter可以实现只读计算属性
- 仅定义setter可以实现只写属性(比如内部敏感数据不允许外部读取,仅允许写入做校验)
如果TypeScript强制要求子类必须同时实现get和set,就会阻断这些合法的JS开发模式,不符合TypeScript“适配JS所有原生特性”的设计目标。
- 向后兼容的历史包袱
这种宽松的校验逻辑从TypeScript早期版本就已存在,大量存量代码已经依赖了这个特性。如果后续版本改成严格校验访问器的成对实现,会导致大面积的存量代码编译失败,因此官方一直没有调整这个规则。
如果业务场景需要强制要求子类必须同时实现get和set,可以通过自定义类型约束、或者代码审查规则来实现,TS默认没有提供对应的编译开关。
内容的提问来源于stack exchange,提问作者Jacob L
相关产品推荐
相关产品推荐

