在TypeScript中的Duck Typing
什么是Duck Typing
首先,我们要知道什么是Duck Typing。根据程序员的说法,当一个对象的类型是由它的行为(比如方法和属性)决定的,而不是由它的类决定的,这种情况被称为“鸭子类型”。
在TypeScript中的Duck Typing
TypeScript中接口的使用使得鸭子类型成为可能。接口表示一个对象必须具备的方法和特征的集合。
例如,如果一个接口定义了一个函数,那么任何具有名为”myFunc()”的方法的对象都可以被视为属于特定的类型,而不考虑它的类。当两个对象具有相同的行为并且可以互换使用时,可以实现更大的代码灵活性。
鸭子类型强调通过考虑对象的方法和属性而不是实际类型来评估对象是否适合于某个任务。接口定义了一个对象必须具备的属性和方法,以被认为是“鸭子类型”用于特定目的。
鸭子类型的好处
鸭子类型的主要好处之一是使代码更加灵活和可重用。代码可以使用具有所需方法和属性的任何对象,而不仅仅是特定类型的对象,并且可以在不修改代码的情况下在不同的情况下使用。鸭子类型还通过在单个代码库中允许对不同类型的对象进行可互换的使用,从而提高了代码的重用性。
TypeScript中的鸭子类型示例
以下是如何在TypeScript中使用鸭子类型的示例 –
定义一个表示你希望一个对象具有的行为的接口。例如 –
interface Duck {
quack(): void;
}
创建一个实现接口的类。例如 –
class MallardDuck implements Duck {
quack(): void {
console.log("Quack!");
}
}
创建类的实例并将其用作接口定义的类型。
let duck: Duck = new MallardDuck();
duck.quack(); // Output: "Quack!"
创建另一个实现该接口的类 –
class RubberDuck implements Duck {
quack(): void {
console.log("Squeak!");
}
}
使用新的类实例作为接口定义的相同类型。
let duck: Duck = new RubberDuck();
duck.quack(); // Output: "Squeak!"
如您所见,MallardDuck和RubberDuck类均实现了Duck接口,而duck变量可以赋值给这两个类的实例。类型是由接口中定义的行为(方法和属性)来确定,而不是由类来确定。
还需注意,在TypeScript中,您可以使用typeof关键字在运行时检查对象的类型,以及对象是否具有所期望的方法或属性。
示例
在此示例中,Bird和Plane类实现了Flyable接口,该接口需要一个fly()方法。在goFly()函数中,这两种“鸭子类型”可以互换使用。函数对于传递给它的对象的实际类型并不关心,只要它具有可调用的fly()方法即可。
interface Flyable {
fly(): void;
}
class Bird implements Flyable {
fly(): void {
console.log("Bird is flying");
}
}
class Plane implements Flyable {
fly(): void {
console.log("Plane is flying");
}
}
function goFly(flyable: Flyable) {
flyable.fly();
}
let bird = new Bird();
let plane = new Plane();
goFly(bird); // Prints "Bird is flying"
goFly(plane); // Prints "Plane is flying"
在编译时,它会生成以下的JavaScript代码−
var Bird = /** @class */ (function () {
function Bird() {
}
Bird.prototype.fly = function () {
console.log("Bird is flying");
};
return Bird;
}());
var Plane = /** @class */ (function () {
function Plane() {
}
Plane.prototype.fly = function () {
console.log("Plane is flying");
};
return Plane;
}());
function goFly(flyable) {
flyable.fly();
}
var bird = new Bird();
var plane = new Plane();
goFly(bird); // Prints "Bird is flying"
goFly(plane); // Prints "Plane is flying"
结果
上述代码将产生以下输出:
Bird is flying
Plane is flying
示例
总的来说,鸭子类型是一种强大的编程概念,在TypeScript代码中允许不同类型的对象可以互换使用,只要它们具有相同的方法和属性,从而实现更高的灵活性和可重用性。在这个示例中,Driveable接口,Car和Truck类展示了同样的事情。
interface Driveable {
drive(): void;
}
class Car implements Driveable {
drive(): void {
console.log("Car is driving");
}
}
class Truck implements Driveable {
drive(): void {
console.log("Truck is driving");
}
}
function goDrive(driveable: Driveable) {
driveable.drive();
}
let car = new Car();
let truck = new Truck();
goDrive(car); // Prints "Car is driving"
goDrive(truck); // Prints "Truck is driving"
在编译时,它将生成以下的JavaScript代码−
var Car = /** @class */ (function () {
function Car() {
}
Car.prototype.drive = function () {
console.log("Car is driving");
};
return Car;
}());
var Truck = /** @class */ (function () {
function Truck() {
}
Truck.prototype.drive = function () {
console.log("Truck is driving");
};
return Truck;
}());
function goDrive(driveable) {
driveable.drive();
}
var car = new Car();
var truck = new Truck();
goDrive(car); // Prints "Car is driving"
goDrive(truck); // Prints "Truck is driving"
输出
上述代码将产生以下输出 –
Car is driving
Truck is driving
鸭子类型的主要思想是代码应该被编写为适用于任何具有所需方法和属性的对象,而不是被编写为针对特定对象工作。这可以使代码更加灵活和可重用,允许您在不更改代码的情况下交替使用不同类型的对象。