我刚开始学习 TypeScript 并且在尝试使用不同的语言特性。下面是我在其中一个在线课程中一直在努力的代码示例。
我正在尝试让继承和重载正常工作,但是我遇到了问题。在整个代码中,我使用了一个基类 Auto 下的车辆,以及一个子类 Truck 下的卡车。
我想要看看是否可以将车辆强制转换为卡车并访问专门的函数 HonkHorn。 此外,我还试图将卡车转换回 Auto 并访问基础函数 WriteDetails。
在这两种情况下,似乎对象都保持了其原始类型。因此,typecast4.HonkHorn();
会生成运行时错误:
Uncaught TypeError: typecast4.HonkHorn is not a function.
尝试将 Truck 强制转换为 Auto 将始终导致调用专门的覆盖 WriteDetails。转换代码在示例底部。
可以有人帮帮我理解为什么会出现这种情况吗?
提前感谢您的帮助!
// defines the structure of auto options
interface IAutoOptions{
engine: Engine,
color: string,
price: number,
year: number
}
// extends autooptions with truck specific options
interface ITruckOptions extends IAutoOptions{
fourbyfour: boolean,
bedlength: string
}
// defines the structure of engines
interface IEngine {
enginetype: string;
horsepower: number;
hydraulicpump?: string
start(warmuptime: number, callback: () => void): void;
stop(): void;
}
// the engine class must implement the members as specified in the IEngine interface
class Engine implements IEngine{
enginetype: string;
horsepower: number;
hydraulicpump?: string; //optional hydraulic parameter
constructor(enginetype: string, horsepower: number, hydraulicpump? : string ) {
this.enginetype = enginetype;
this.horsepower = horsepower;
if (!(hydraulicpump)){
hydraulicpump = "Not Available"; //if no hydraulic parameter is provided we set it to "Not Available"
}
this.hydraulicpump = hydraulicpump;
}
// start requires a callback parameter which accepts a specialized callback object/function that accepts and returns nothing
// by accepting a callback object/function that code can be seperated off, which makes this class much cleaner and organized
start(warmuptime: number, callback: () => void) {
window.setTimeout(() => {
callback();
document.write(this.enginetype + " has started!" + "</br>");
}, warmuptime);
};
stop() {
document.write(this.enginetype + " has stopped!" + "</br>");
};
}
// base class for autos
class Auto {
engine: Engine;
color: string;
price: number;
year: number;
constructor(options: IAutoOptions) {
this.engine = options.engine;
this.color = options.color;
this.price = options.price;
this.year = options.year;
}
//WriteDetails contains the base details for each Auto which can be overriden in specialized classes
WriteDetails() {
document.write("Color: " + this.color + "</br>");
document.write("Year: " + this.year + "</br>");
document.write("Price: $" + this.price + "</br>");
document.write("Engine Type: " + this.engine.enginetype + "</br>");
document.write("Horse Power: " + this.engine.horsepower + "</br>");
document.write("Hydraulic Pump: " + this.engine.hydraulicpump + "</br>");
};
}
// Truck extends Auto to add Truck specific fields and function overloads
// Note that it does not contains all the base fields from Auto thus making it much smaller and cleaner
// Only truck specific code is added.
class Truck extends Auto{
fourbyfour: boolean;
bedlength: string;
constructor(options: ITruckOptions) {
// to overload the constructor super() must to be called, which calls the base class constructor in Auto
super(options);
this.bedlength = options.bedlength;
this.fourbyfour = options.fourbyfour;
}
// WriteDetails overrides the Auto WriteDetails, but first calls the base WriteDetails function
WriteDetails() {
super.WriteDetails();
document.write("Bed Length: " + this.bedlength + "</br>");
document.write("4x4 : " + this.fourbyfour + "</br>");
};
HonkHorn() {
document.write("Honk Honk!</br>");
}
}
// below is one of the notations to define a callback object that can be used to call
// the start function on the Engine class
// this callback function has encapsulated car specific logic for starting the engine
// much cleaner than putting the specialized code in the Auto class
var CarEngineStart = () => {
document.write("<h1>Starting Car</h1>");
document.write("Check Tires!" + "</br>");
document.write("Fasten Seatbelts!" + "</br>");
document.write("Check Mirrors!" + "</br>");
document.write("Starting Engine!" + "</br>");
};
// yet another way to define a callback object (function)
// this callback function has encapsulated truck specific logic for starting the engine
// much cleaner than putting the specialized code in the Auto or Truck classes
function TruckEngineStart() {
document.write("<h1>Starting Truck</h1>");
document.write("Check Tires!" + "</br>");
document.write("Check if load is properly fastened!" + "</br>");
document.write("Check timesheet!" + "</br>");
document.write("Fasten Seatbelts!" + "</br>");
document.write("Check Mirrors!" + "</br>");
document.write("Starting Engine!" + "</br>");
}
// ###################### Start logic
// creating an engine
var carengine = new Engine("V8", 300);
// creating another engine, but now providing the optional hydraulicpump parameter
var truckengine = new Engine("V12", 1000, "Flexpump 3000");
var car = new Auto({
engine: carengine,
color: 'Blue',
price: 20000,
year: 2017
});
var truck = new Truck({
engine: truckengine,
color: 'Red',
price: 80000,
year: 2015,
bedlength: 'Long Bed',
fourbyfour: true
});
document.write("<h1>Car Details</h1>");
car.WriteDetails();
document.write("<h1>Truck Details</h1>");
truck.WriteDetails();
truck.engine.start(10000, TruckEngineStart);
car.engine.start(5000, CarEngineStart);
window.setTimeout(() => {
document.write("<h1>Stopping Car</h1>");
car.engine.stop();
document.write("<h1>Stopping Truck</h1>");
truck.engine.stop();
}, 15000);
document.write("<h1>Casting Autos</h1>");
document.write("<h2>Auto WriteDetails for Car</h2>");
var typecast: Auto;
typecast = car;
typecast.WriteDetails();
document.write("<h2>Truck WriteDetails for Car with type cast</h2>");
var typecast4: Truck;
typecast4 = <Truck>car;
typecast4.HonkHorn();
typecast4.WriteDetails();
document.write("<h2>Auto WriteDetails for Truck without type cast</h2>");
var typecast2: Auto;
typecast2 = truck;
typecast2.WriteDetails();
document.write("<h2>Auto WriteDetails for Truck with type cast</h2>");
var typecast3: Auto;
typecast3 = <Auto>truck;
typecast3.WriteDetails();