返回

在 TS 中协作力量,接口和类的默契配合

前端

前言
在前面的章节中,我们探索了 TypeScript 中的对象类型和接口,了解了如何使用接口对对象的属性类型进行。现在,我们将更进一步,探讨接口的另一个重要作用:当对象遇到接口时,会碰撞出怎样的精彩火花。

接口的双重角色
接口在 TypeScript 中扮演着双重角色:

  1. 契约(Contract) :接口定义了一组方法和属性的契约,任何实现该接口的类都必须遵守这个契约。这有助于确保代码的一致性和可靠性。
  2. 类型(Type) :接口也是一种类型,它了一组对象应该具有的属性和方法。这意味着您可以将接口作为类型来使用,就像使用类一样。

接口与类的协作
接口和类在 TypeScript 中可以协同工作,共同打造更加灵活、强大的代码。以下是一些常见的协作方式:

1. 接口继承(Interface Inheritance)
接口可以继承自其他接口,从而扩展其功能。这与类的继承非常相似。例如:

interface Animal {
  name: string;
  age: number;
}

interface Dog extends Animal {
  breed: string;
}

Dog 接口继承自 Animal 接口,因此它具有 nameage 两个属性,还额外添加了一个 breed 属性。

2. 多态(Polymorphism)
多态是面向对象编程的重要概念,它允许您使用父类或接口类型来引用子类对象。这使得您可以编写更加灵活、可扩展的代码。例如:

function printAnimal(animal: Animal) {
  console.log(`Name: ${animal.name}`);
  console.log(`Age: ${animal.age}`);
}

const dog = new Dog('Buddy', 3, 'Golden Retriever');
printAnimal(dog); // 输出:"Name: Buddy", "Age: 3"

在上面的代码中,printAnimal() 函数接受一个 Animal 类型或其子类的参数。当我们传入一个 Dog 对象时,printAnimal() 函数能够正确地打印出狗狗的名字和年龄,这是因为 Dog 类实现了 Animal 接口。

3. 抽象类(Abstract Class)
抽象类是一种特殊的类,它不能被直接实例化,但可以被子类继承。抽象类中的方法可以是抽象的,这意味着它们没有实现,而是由子类来实现。例如:

abstract class Shape {
  abstract draw(): void;
}

class Circle extends Shape {
  radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  draw(): void {
    console.log('Drawing a circle with radius:', this.radius);
  }
}

class Rectangle extends Shape {
  width: number;
  height: number;

  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  draw(): void {
    console.log('Drawing a rectangle with width:', this.width, 'and height:', this.height);
  }
}

const circle = new Circle(5);
circle.draw(); // 输出:"Drawing a circle with radius: 5"

const rectangle = new Rectangle(10, 15);
rectangle.draw(); // 输出:"Drawing a rectangle with width: 10 and height: 15"

在上面的代码中,Shape 是一个抽象类,它定义了一个抽象方法 draw()CircleRectangle 是两个具体类,它们继承自 Shape 类并实现了 draw() 方法。这使得我们可以使用抽象类来定义公共接口,而将具体的实现留给子类。

4. 接口作为类型(Interface as Type)
正如前面提到的,接口也是一种类型。这意味着您可以将接口作为类型来使用,就像使用类一样。例如:

interface Person {
  name: string;
  age: number;
}

function getPersonInfo(person: Person): string {
  return `Name: ${person.name}, Age: ${person.age}`;
}

const person = {
  name: 'John',
  age: 30
};

const personInfo = getPersonInfo(person);
console.log(personInfo); // 输出:"Name: John, Age: 30"

在上面的代码中,Person 接口定义了一个人的基本信息,包括姓名和年龄。getPersonInfo() 函数接受一个 Person 类型或其子类的参数,并返回一个字符串,其中包含了该人的姓名和年龄。当我们传入一个对象时,该对象必须符合 Person 接口的定义,否则编译器会报错。

结语
接口和类在 TypeScript 中携手合作,共同打造更加灵活、强大的代码。它们之间的默契配合,可以让您轻松实现多态、抽象和代码复用,助您打造更加健壮、可扩展的应用程序。