TypeScript中父类子类方法与普通函数的赋值兼容性差异原因
为什么TypeScript对普通函数和类继承方法的参数兼容性检测不同?
普通函数的参数兼容性检测
当你把一个函数赋值给另一个函数类型时,TypeScript会严格遵循参数逆变规则:目标函数的参数类型必须能被源函数的参数类型接受(换句话说,源函数的参数类型必须是目标函数参数类型的超集)。
比如下面的例子,srcFunc的参数是更窄的"abc"|"def"类型,而targetFunc的参数是更宽泛的string类型。由于string不能赋值给"abc"|"def",TypeScript会直接报错:
function targetFunc(name:string) {console.log(name)} function srcFunc(name:"abc"|"def") {console.log(name)} let t:typeof targetFunc = srcFunc;
报错信息:
Type '(name: "abc" | "def") => void' is not assignable to type '(name: string) => void'.
Types of parameters 'name' and 'name' are incompatible.
Type 'string' is not assignable to type '"abc" | "def"'.(2322)
类继承方法的特殊处理
但在类的方法重写场景中,TypeScript默认采用了参数双向协变的规则,也就是既允许子类方法的参数比父类更宽泛,也允许更窄——这和普通函数的严格逆变规则不同。
比如你给出的例子:
class Base { print(name:string) {console.log(`base:${name}`)} } class Child extends Base { print(name:"abc"|"def") { console.log(`Child:${name}`) } } let c:Child = new Child; let b:Base = c; b.print("apple") // 传入"apple"不符合Child.print的参数类型,但TS未报错
为什么会有这种差异?
这个设计是为了兼容大量现有JavaScript代码,同时符合面向对象编程的常见实践:
- 很多开发者在重写父类方法时,会有意缩小参数范围来实现更具体的逻辑,TypeScript不想强制阻止这种写法。
- 虽然这在严格类型安全上有一点妥协,但大多数场景下,开发者会自己保证调用的合理性,或者通过其他方式约束输入。
如果你想让TypeScript对类方法也启用严格的参数逆变检测,可以在tsconfig.json中开启"strictFunctionTypes": true配置。开启后,上面的类方法重写代码就会触发和普通函数一样的兼容性错误。
内容的提问来源于stack exchange,提问作者macyou
相关产品推荐
相关产品推荐

