为什么TypeScript允许继承的方法不完整实现接口要求?
类型检查器判定初始代码合法的核心原因
这是TypeScript的默认设计:类和接口中使用方法语法定义的函数,参数类型默认采用双变(Bivariance)兼容规则。
先明确类型关系:你定义的AB是B的子类型,AB包含B的全部字段,还额外存在a字段。
按照严格的类型理论,函数参数的兼容性应该遵循逆变规则:如果要求实现一个(x: B) => void类型的方法,提供的实现参数类型必须是B或者B的父类型(可以接收更宽泛的参数),不能是B的子类型(只能接收更窄的参数)。按这个规则,Superclass的foo方法类型是(x: AB) => void,无法兼容接口I要求的(x: B) => void,理应触发报错。
但TypeScript为了兼容JavaScript生态中大量常见的宽松用法(比如数组协变、经典的类继承模式),默认对方法参数关闭了严格逆变检查,只要两个参数类型存在子父类关系,无论方向都认为兼容,这就是你初始代码没有报错的原因。
如果你想要触发你预期的严格检查,可做两个调整:
- 在
tsconfig.json中开启strictFunctionTypes编译选项(属于strict模式的子配置项) - 将接口中的方法定义为函数字面量形式:
interface I { foo: (x: B) => void; }
调整后初始代码会直接抛出类型错误,提示Subclass实现的foo方法不满足接口I的要求。
为什么子类显式实现foo方法时调用super.foo会报错
这个检查和双变规则无关,是普通的实参类型匹配检查:super.foo要求入参是AB类型,你传入的是B类型,B不是AB的子类型(缺少a字段),自然会触发类型错误。
内容的提问来源于stack exchange,提问作者Martin Geisse
相关产品推荐
相关产品推荐

