TypeScript 类

TypeScript 为 JavaScript 类添加了类型和可见性修饰符。

在此处了解有关 JavaScript 类的更多信息。

成员:类型

类的成员(属性和方法)使用类型注解进行类型化,类似于变量。

实例

class Person {
  name: string;
}

const person = new Person();
person.name = "Jane";

亲自试一试

成员:可见性

类成员还可以被赋予特殊的修饰符,这些修饰符会影响其可见性。

TypeScript 中主要有三个可见性修饰符。

  • public - (默认)允许从任何地方访问类成员
  • private - 仅允许从类内部访问类成员
  • protected - 允许从类本身和任何继承它的类中访问类成员,这在下面的继承部分中有介绍

实例

class Person {  
  private name: string;  
  
  public constructor(name: string) {  
    this.name = name;  
  }  
  
  public getName(): string {  
    return this.name;  
  }  
}  
  
const person = new Person("Jane");  
console.log(person.getName()); // 由于 name 是私有的,因此无法从类外部访问 person.name

亲自试一试

类中的 this 关键字通常指的是类的实例。在此处阅读更多有关 this 的信息。

参数属性

TypeScript 提供了一种在构造函数中定义类成员的便捷方式,方法是在参数中添加可见性修饰符。

实例

class Person {  
  // name 是一个私有成员变量  
  public constructor(private name: string) {}  
  
  public getName(): string {  
    return this.name;  
  }  
}  
  
const person = new Person("Jane");  
console.log(person.getName());

亲自试一试

只读

与数组类似,readonly 关键字可以防止类成员被更改。

实例

class Person {  
  private readonly name: string;  
  
  public constructor(name: string) {  
    // 名称在初始定义后无法更改,这必须在声明时或在构造函数中进行。  
    this.name = name;  
  }  
  
  public getName(): string {  
    return this.name;  
  }  
}  
  
const person = new Person("Jane");  
console.log(person.getName());

亲自试一试

继承:实现

接口(此处介绍)可用于通过 implements 关键字定义类必须遵循的类型。

实例

interface Shape {
  getArea: () => number;
}

class Rectangle implements Shape {
  public constructor(protected readonly width: number, protected readonly height: number) {}

  public getArea(): number {
    return this.width * this.height;
  }
}

亲自试一试

一个类可以通过在 implements 后列出每一个接口,并用逗号分隔,来实现多个接口,如下所示:

class Rectangle implements Shape, Colored {

继承:扩展

类可以通过 extends 关键字相互继承。一个类只能扩展一个其他类。

实例

interface Shape {
  getArea: () => number;
}

class Rectangle implements Shape {
  public constructor(protected readonly width: number, protected readonly height: number) {}

  public getArea(): number {
    return this.width * this.height;
  }
}

class Square extends Rectangle {
  public constructor(width: number) {
    super(width, width);
  }

  // getArea 从 Rectangle 继承
}

亲自试一试

重写

当一个类扩展另一个类时,它可以替换父类中具有相同名称的成员。

较新版本的 TypeScript 允许使用 override 关键字显式标记这一点。

实例

interface Shape {  
  getArea: () => number;  
}  
  
class Rectangle implements Shape {  
  // 使用 protected 修饰符的这些成员允许从继承自此类的类(如 Square)进行访问  
  public constructor(protected readonly width: number, protected readonly height: number) {}  
  
  public getArea(): number {  
    return this.width * this.height;  
  }  
  
  public toString(): string {  
    return `Rectangle[width=${this.width}, height=${this.height}]`;  
  }  
}  
  
class Square extends Rectangle {  
  public constructor(width: number) {  
    super(width, width);  
  }  
  
  // 这个 toString 替换了 Rectangle 的 toString  
  public override toString(): string {  
    return `Square[width=${this.width}]`;  
  }  
}

亲自试一试

默认情况下,当重写方法时,override 关键字是可选的,它仅有助于防止意外重写不存在的方法。使用 noImplicitOverride 设置来强制在重写时使用它。

抽象类

类的编写方式可以允许它们用作其他类的基类,而不必实现所有成员。这是通过使用 abstract 关键字来完成的。未实现的成员也使用 abstract 关键字。

实例

abstract class Polygon {
  public abstract getArea(): number;

  public toString(): string {
    return `Polygon[area=${this.getArea()}]`;
  }
}

class Rectangle extends Polygon {
  public constructor(protected readonly width: number, protected readonly height: number) {
    super();
  }

  public getArea(): number {
    return this.width * this.height;
  }
}

亲自试一试

抽象类不能直接实例化,因为它们没有实现所有成员。