Typescript - 5. 类(Classes)

55 阅读2分钟

在 TypeScript 中,类(Classes)是构建对象的蓝图。类可以包含属性(成员变量)、构造函数和方法。TypeScript 的类基于 ECMAScript 6 标准,并添加了一些额外的功能,使其更加强大和灵活。

定义类

一个基本的类定义如下:

class Greeter {
    greeting: string;

    constructor(message: string) {
        this.greeting = message;
    }

    greet() {
        return `Hello, ${this.greeting}`;
    }
}

let greeter = new Greeter("world");
console.log(greeter.greet()); // "Hello, world"

继承

TypeScript 支持类的继承,这使得可以在一个类的基础上构建另一个类。使用 extends 关键字来实现继承。

class Animal {
    move(distance: number = 0) {
        console.log(`Animal moved ${distance} meters.`);
    }
}

class Dog extends Animal {
    bark() {
        console.log("Woof! Woof!");
    }
}

const dog = new Dog();
dog.bark(); // "Woof! Woof!"
dog.move(10); // "Animal moved 10 meters."

公共(public)、私有(private)和受保护的(protected)修饰符

TypeScript 提供了三种访问修饰符来控制类成员的可见性:

  1. public: 默认情况下,所有的类成员都是公有的。
  2. private: 私有成员只能在声明它们的类中访问。
  3. protected: 受保护的成员可以在声明它们的类及其子类中访问。
class Animal {
    public name: string;
    private age: number;
    protected type: string;

    constructor(name: string, age: number, type: string) {
        this.name = name;
        this.age = age;
        this.type = type;
    }

    getAge() {
        return this.age;
    }
}

class Dog extends Animal {
    constructor(name: string, age: number) {
        super(name, age, "Dog");
    }

    getType() {
        return this.type;
    }
}

let dog = new Dog("Buddy", 3);
console.log(dog.name); // "Buddy"
// console.log(dog.age); // Error: Property 'age' is private and only accessible within class 'Animal'.
console.log(dog.getAge()); // 3
console.log(dog.getType()); // "Dog"

readonly 修饰符

readonly 修饰符用于将属性设置为只读。一旦赋值后就不能再修改。

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;

    constructor(name: string) {
        this.name = name;
    }
}

let octopus = new Octopus("Octo");
// octopus.name = "NewName"; // Error: Cannot assign to 'name' because it is a read-only property.
console.log(octopus.name); // "Octo"

存取器(Getters 和 Setters)

TypeScript 允许你通过 getset 关键字来定义存取器,以控制对某个属性的访问。

class Employee {
    private _fullName: string;

    get fullName(): string {
        return this._fullName;
    }

    set fullName(newName: string) {
        this._fullName = newName;
    }
}

let employee = new Employee();
employee.fullName = "John Doe";
console.log(employee.fullName); // "John Doe"

静态属性和方法

静态成员存在于类本身而不是类的实例上。使用 static 关键字来定义静态成员。

class Grid {
    static origin = { x: 0, y: 0 };

    calculateDistanceFromOrigin(point: { x: number; y: number }): number {
        let xDist = point.x - Grid.origin.x;
        let yDist = point.y - Grid.origin.y;
        return Math.sqrt(xDist * xDist + yDist * yDist);
    }
}

let grid = new Grid();
console.log(Grid.origin); // { x: 0, y: 0 }

抽象类

抽象类作为其他派生类的基类使用。它们不能直接被实例化。使用 abstract 关键字定义抽象类和抽象方法。

abstract class Department {
    constructor(public name: string) {}

    printName(): void {
        console.log("Department name: " + this.name);
    }

    abstract printMeeting(): void; // 必须在派生类中实现
}

class AccountingDepartment extends Department {
    constructor() {
        super("Accounting and Auditing"); // 派生类必须调用基类的构造函数
    }

    printMeeting(): void {
        console.log("The Accounting Department meets each Monday at 10am.");
    }

    generateReports(): void {
        console.log("Generating accounting reports...");
    }
}

let department: Department;
// department = new Department(); // Error: Cannot create an instance of an abstract class
department = new AccountingDepartment();
department.printName(); // "Department name: Accounting and Auditing"
department.printMeeting(); // "The Accounting Department meets each Monday at 10am."
// department.generateReports(); // Error: Method doesn't exist on declared abstract class

通过这些特性,TypeScript 的类系统提供了强大的面向对象编程支持,使得开发者能够创建结构良好、可扩展和可维护的代码。