学习 TypeScript - 转换类型

Learning TypeScript - Casting Types

我是 TypeScript 的新手,正在尝试各种语言功能。下面是我在许多在线课程之一中一直在研究的代码示例。

我在获取继承和重载以正常工作时遇到了问题。 在整个代码中,我使用了一辆基本 class Auto 的汽车,以及一辆 off child class 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();

Typescript 中没有类型转换,只有类型断言。这用于类型检查,不会影响运行时行为。

例如类型断言:

car as Truck  // older syntax syntax: <Truck> car 

告诉编译器carTruck类型,但不会影响生成的JS代码。

TypeScript allows you to override its inferred and analyzed view of types in any way you want to. This is done by a mechanism called "type assertion". TypeScript's type assertion is purely you telling the compiler that you know about the types better than it does, and that it should not second guess you.

Type Assertion vs. Casting

The reason why it's not called "type casting" is that casting generally implies some sort of runtime support. However type assertions are purely a compile time construct and a way for you to provide hints to the compiler on how you want your code to be analyzed.

https://basarat.gitbooks.io/typescript/content/docs/types/type-assertion.html

更新:

现在另一个很好的参考是 Typescript site itself

Type assertions are a way to tell the compiler “trust me, I know what I’m doing.” A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler. TypeScript assumes that you, the programmer, have performed any special checks that you need.

对于更改类型,此处的这些答案可能会有用:How do I cast a JSON Object to a TypeScript class?