为什么Typescript允许使用子类参数覆盖方法

时间:2019-04-01 17:11:18

标签: typescript

我惊讶地发现Typescript允许子类在覆盖方法时在参数列表中指定更窄的类型。我必须想象这不是监督,而是Typescript团队的故意选择。但为什么?允许这种模式有什么好处?

例如:

interface Vehicle {
  model: string;
}

interface TowTruck extends Vehicle {
  towing: Vehicle;
}

class VehicleHelper {
  stringify(vehicle: Vehicle) {
    return vehicle.model;
  }
}

class TowTruckHelper extends VehicleHelper {
  // override parameter to be more specific than "Vehicle"
  stringify(towTruck: TowTruck) {
    return (
      super.stringify(towTruck)
      + ' towing a '
      + super.stringify(towTruck.towing)
    );
  }
}

const myHelper: VehicleHelper = new TowTruckHelper();
console.log(myHelper.stringify({ model: 'Camry' }));

没有报告Typescript错误,但是运行它会抛出Uncaught TypeError: Cannot read property 'model' of undefined

1 个答案:

答案 0 :(得分:3)

我相信这是设计使然。 Clas方法是双变量相关的。最初,所有函数都是双变量相关的,但是strictFunctionTypes加强了对于不是源自方法定义的函数签名:

  

更严格的检查适用于所有函数类型,但源于方法或构造函数声明的函数类型除外。专门排除了方法,以确保通用类和接口(例如Array)继续保持大多数协变关系。严格检查方法的影响将是一个重大突破,因为大量泛型类型将变为不变(即使如此,我们可能会继续探索这种更严格的模式)。

实际上,如果您使用函数字段而不是方法,则对strictFunctionTypes进行定义会出现错误:

interface Vehicle {
    model: string;
}

interface TowTruck extends Vehicle {
    towing: Vehicle;
}

class VehicleHelper {
    stringify = function (vehicle: Vehicle) {
        return vehicle.model;
    }
}

class TowTruckHelper extends VehicleHelper {
    // Property 'stringify' in type 'TowTruckHelper' is not assignable to the same property in base type 'VehicleHelper'.
    stringify = function (this: TowTruckHelper, towTruck: TowTruck) {
        return (
            VehicleHelper.prototype.stringify.apply(this, towTruck)
            + ' towing a '
            + VehicleHelper.prototype.stringify.apply(this, towTruck.towing)
        );
    }
}

const myHelper: VehicleHelper = new TowTruckHelper();
console.log(myHelper.stringify({ model: 'Camry' }));

Here也是与您描述标记为按预期工作的确切行为相关的问题。