如何扩展接口以创建接口组合?

typescriptweb developmentfront end technology

在 TypeScript 中,接口提供了一种定义对象结构和强制类型约束的强大方法。它们允许我们指定对象必须具备的属性和方法。接口的一个有趣特性是能够扩展它们,这使我们能够创建接口组合。在本教程中,我们将探索如何扩展接口以创建从现有接口继承属性和方法的新接口。

语法

interface NewInterface extends ExistingInterface {
// 附加属性和方法
}

interface NewInterface extends Interface1, Interface2, ... {
// 附加属性和方法
}

上面显示了通过扩展现有接口创建新接口的语法。同时还显示了扩展多个接口的语法。第二种语法是扩展多个接口。

示例 1:扩展单个接口

让我们从一个简单的场景开始。我们有一个名为 Shape 的接口,它为各种形状定义了一个通用的属性 color。我们想要创建一个新的接口 ColoredShape,它扩展 Shape 并添加一个额外的属性 name。

让我们看一个扩展 Shape 接口以创建 ColoredShape 接口的示例。在此示例中,我们定义了一个带有 color 属性的 Shape 接口。然后,我们通过扩展 Shape 并添加一个 name 属性来创建 ColoredShape 接口。我们实例化了一个 ColoredShape 类型的对象 square,并为 color 和 name 属性赋值。最后,我们使用点表示法访问并打印了 color 和 name 的值。

interface Shape {
   color: string;
}

interface ColoredShape extends Shape {
   name: string;
}

const square: ColoredShape = {
   color: "red",
   name: "Square",
};

console.log(square.color);
console.log(square.name); 

编译后,它将生成以下 JavaScript 代码 -


var square = {
   color: "red",
   name: "Square"
};
console.log(square.color);
console.log(square.name);

输出

上述代码将产生以下输出 -

red
Square

示例 2:扩展多个接口

在 TypeScript 中,我们还可以扩展多个接口,创建一个新的接口,该接口将所有扩展接口的属性和方法组合在一起。这使我们能够通过重用现有接口来创建更复杂、更专业的接口。

在下面的示例中,我们定义了 Printable 和 Scanable 接口,每个接口都有各自的方法。然后,我们通过扩展 Printable 和 Scanable 接口并添加新方法 copy() 创建了 MultifunctionalDevice 接口。我们在一个名为 Printer 的类中实现了 MultifunctionalDevice 接口,并为所有方法提供了必要的实现。最后,我们实例化了 Printer 类的一个对象,并调用了 print()、scan() 和 copy() 方法。

interface Printable {
   print(): void;
}

interface Scanable {
   scan(): void;
}

interface MultifunctionalDevice extends Printable, Scanable {
   copy(): void;
}

class Printer implements MultifunctionalDevice {
   print() {
      console.log("Printing...");
   }

   scan() {
      console.log("Scanning...");
   }

  copy() {
     console.log("Copying...");
   }
}

const printer = new Printer();
printer.print(); 
printer.scan(); 
printer.copy(); 

编译后,它将生成以下 JavaScript 代码 -


var Printer = /** @class */ (function () {
   function Printer() {
   }
   Printer.prototype.print = function () {
      console.log("Printing...");
   };
   Printer.prototype.scan = function () {
      console.log("Scanning...");
   };
   Printer.prototype.copy = function () {
      console.log("Copying...");
   };
   return Printer;
}());
var printer = new Printer();
printer.print();
printer.scan();
printer.copy();

输出

上述代码将产生以下输出 -

Printing...
Scanning...
Copying...

示例 3:增强现有接口

我们经常会遇到需要通过添加额外属性或方法来增强现有接口的情况。扩展接口使我们能够在不直接修改原始接口的情况下实现这一点。在本例中,我们有一个现有的 User 接口,其中包含 name 属性。我们扩展该 User 接口以创建一个 EnhancedUser 接口,该接口添加了 age 属性和 greet() 方法。通过扩展该接口,我们可以定义一个 EnhancedUser 类型的对象 user,其中包含两个接口的属性和方法。

interface User {
   name: string;
}
interface EnhancedUser extends User {
   age: number;
   greet(): void;
}
const user: EnhancedUser = {
   name: "John Wick",
   age: 25,
   greet() {
      console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
   }
};
user.greet();

编译后,它将生成以下 JavaScript 代码 -


var user = {
   name: "John Wick",
   age: 25,
   greet: function () {
      console.log("Hello, my name is ".concat(this.name, " and I'm ").concat(this.age, " years old."));
   }
};
user.greet();

输出

上述代码将产生以下输出 -

Hello, my name is John Wick and I'm 25 years old.

示例 4:创建复合接口

扩展接口在创建组合来自多个来源的属性和方法的复合接口时也非常有用。这在使用提供其接口的外部库或模块时尤其有用。在本例中,我们有四个接口:Product、DiscountedProduct、ProductWithReviews 和 FeaturedProduct。每个接口都扩展了一个或多个现有接口,这使我们能够创建一个包含来自多个来源的属性和方法的复合接口。然后,我们定义一个 FeaturedProduct 类型的对象 product,它包含扩展接口中定义的所有属性。

interface Product {
   name: string;
   price: number;
}
interface DiscountedProduct extends Product {
   discount: number;
}
interface ProductWithReviews extends Product {
   reviews: string[];
}
interface FeaturedProduct extends DiscountedProduct, ProductWithReviews {
   featured: boolean;
}
const product: FeaturedProduct = {
   name: "Smartphone",
   price: 599,
   discount: 50,
   reviews: ["Great product!", "Highly recommended."],
   featured: true
};
console.log(product.featured); 
console.log(product.reviews);

编译后,它将生成以下 JavaScript 代码 -


var product = {
   name: "Smartphone",
   price: 599,
   discount: 50,
   reviews: ["Great product!", "Highly recommended."],
   featured: true
};
console.log(product.featured);
console.log(product.reviews);

输出

上述代码将产生以下输出 -

true
[ 'Great product!', 'Highly recommended.' ]

示例 5:重写属性和方法

在扩展接口时,我们还可以重写从基接口继承的属性和方法。这使我们能够修改扩展接口中特定属性或方法,或为其提供不同的实现。

在下面的示例中,我们有一个 Animal 接口,它包含一个 name 属性和一个 makeSound() 方法。我们扩展 Animal 接口来创建一个 Dog 接口。通过重写 Dog 接口中的 makeSound() 方法,我们提供了一个特定于狗的不同实现。然后可以实例化 Dog 类型的对象 dog,并在调用时调用重写的方法。

interface Animal {
   name: string;
   makeSound(): void;
}
interface Dog extends Animal {
   makeSound(): void;
}
const dog: Dog = {
   name: "Buddy",
   makeSound() {
      console.log("Woof woof!");
   }
};
dog.makeSound();

编译后,它将生成以下 JavaScript 代码 -


var dog = {
   name: "Buddy",
   makeSound: function () {
      console.log("Woof woof!");
   }
};
dog.makeSound();

输出

上述代码将产生以下输出 -

Woof woof!

结论

总而言之,在 TypeScript 中扩展接口提供了一种强大的机制,可用于创建接口组合、增强现有接口以及提升代码可重用性。通过扩展接口,我们可以从基接口继承属性和方法,添加其他属性和方法,覆盖现有属性和方法,以及组合来自多个来源的接口。

此功能使我们能够构建灵活且强大的类型系统,使我们能够在组件之间定义清晰的契约并强制执行类型安全。它增强了代码库的模块化、可读性和可维护性,使应用程序的管理和扩展更加轻松。无论是扩展单个接口、组合多个接口、增强现有接口,还是覆盖属性和方法,扩展接口的能力都使开发人员能够创建富有表现力且可重用的代码。


相关文章