Skip to content

TypeScript - 类

类是面向对象编程(OOP)中的一个基本概念,用作创建对象的蓝图。它们封装了与特定实体相关的数据(属性或字段)和行为(方法或函数)。TypeScript 对 ES6 中引入的类语法提供了第一类支持,并通过类型注解和访问修饰符进行了增强。

使用 class 关键字,后跟类名(通常使用 PascalCase)。

class ClassName {
// 字段 (属性)
propertyName: type;
anotherProperty?: type; // 可选属性
readonly readOnlyProp: type = initialValue; // 只读属性
private privateField: type;
protected protectedField: type;
static staticProperty: type = value;
// 构造函数
constructor(param1: type, param2: type, ...) {
// 初始化逻辑
this.propertyName = param1;
// ...
}
// 方法
methodName(param: type): returnType {
// 方法逻辑
return value;
}
private privateMethod(): void { ... }
protected protectedMethod(): void { ... }
static staticMethod(): void { ... }
// 获取器 (Getters) 和 设置器 (Setters)
get computedValue(): type {
return this.propertyName;
}
set computedValue(value: type) {
this.propertyName = value;
}
}

类定义可以包含:

  • Fields (字段/属性): 在类作用域内声明的变量,用于存储类的实例数据。使用类型注解。
  • Constructor (构造函数): 一个特殊的方法,名为 constructor,负责创建和初始化使用该类创建的对象。当您使用 new 关键字时会被调用。
  • Methods (方法): 在类内定义的函数,定义了对象的行为。
  • Access Modifiers (访问修饰符): 控制类成员可见性和可访问性的关键字(public、private、protected)。
  • Readonly Modifier (只读修饰符): 防止属性在首次赋值(通常在构造函数中)后被修改。
  • Static Members (静态成员): 属于类本身而非其实例的属性或方法。通过 ClassName.memberName 访问。
  • Getters/Setters (获取器/设置器): 提供对对象属性进行受控访问的特殊方法。
class Vehicle {
// 属性,默认访问级别 (public)
make: string;
model: string;
year: number;
private _vin: string; // 私有属性约定
readonly id: string;
// 静态属性
static numberOfVehicles = 0;
constructor(make: string, model: string, year: number, vin: string) {
this.make = make;
this.model = model;
this.year = year;
this._vin = vin;
this.id = `veh-${Math.random().toString(36).substr(2, 9)}`; // 为只读属性赋值
Vehicle.numberOfVehicles++; // 增加静态属性值
}
// 方法
displayInfo(): void {
console.log(`Vehicle: ${this.year} ${this.make} ${this.model} (ID: ${this.id})`);
}
// 私有属性的获取器
get vin(): string {
return this._vin;
}
// 静态方法
static getVehicleCount(): number {
return Vehicle.numberOfVehicles;
}
}
// 访问静态成员
console.log(`Initial vehicle count: ${Vehicle.getVehicleCount()}`); // 输出: 0

使用 new 关键字后跟类名和括号(如果需要,传递参数给构造函数)。

const car1 = new Vehicle("Toyota", "Camry", 2022, "123ABC456DEF");
const car2 = new Vehicle("Honda", "Civic", 2021, "789GHI012JKL");
console.log(`Current vehicle count: ${Vehicle.getVehicleCount()}`); // 输出: 2

使用点(.)符号在对象实例上访问其公共属性和方法。

console.log(car1.make); // 输出: Toyota
car1.displayInfo(); // 输出: Vehicle: 2022 Toyota Camry (ID: veh-...)
console.log(car2.model); // 输出: Civic
car2.displayInfo(); // 输出: Vehicle: 2021 Honda Civic (ID: veh-...)
// 通过获取器访问
console.log(`Car 1 VIN: ${car1.vin}`);
// car1.id = "new-id"; // Error: Cannot assign to 'id' because it is a read-only property. ('id' 是只读属性,无法赋值)
// console.log(car1._vin); // Error: Property '_vin' is private and only accessible within class 'Vehicle'. ('_vin' 是私有属性,只能在 'Vehicle' 类内部访问)
  • public (默认): 成员可以从任何地方访问。
  • private: 成员只能在其定义类内部访问。
  • protected: 成员在其定义类内部以及派生(子)类的实例中可以访问。

TypeScript 提供了一种简洁的语法,通过在构造函数参数前添加访问修饰符(public、private、protected)或 readonly,直接声明和初始化类成员。

class Employee {
// 自动创建并初始化 'name' 和 'department' 属性
constructor(
public readonly id: number,
public name: string,
private department: string
) {}
getDept(): string {
// 在类内部可以访问私有成员
return this.department;
}
}
const emp1 = new Employee(101, "Alice", "Engineering");
console.log(emp1.name); // 输出: Alice
console.log(emp1.id); // 输出: 101
console.log(emp1.getDept()); // 输出: Engineering
// console.log(emp1.department); // 错误: Property 'department' is private... ('department' 是私有属性...)

类可以使用 extends 关键字继承单个父类(基类或超类)的属性和方法。继承的类称为子类或派生类。

派生类继承所有公共(public)和受保护(protected)成员。私有(private)成员不被继承。构造函数不被继承,但如果父类有构造函数,则派生类的构造函数必须使用 super() 调用父类构造函数。

class Animal {
constructor(public name: string) {}
move(distanceInMeters: number = 0): void {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
// 派生类构造函数必须调用 super()
constructor(name: string) {
super(name); // 调用父类 (Animal) 的构造函数
}
bark(): void {
console.log("Woof! Woof!");
}
// 重写父类方法
move(distanceInMeters = 5): void {
console.log("Running...");
super.move(distanceInMeters); // 调用父类的 move 方法
}
}
const myDog = new Dog("Buddy");
myDog.bark(); // 输出: Woof! Woof!
myDog.move(10); // 输出: Running...
// 输出: Buddy moved 10m.
console.log(myDog.name); // 输出: Buddy (继承自 Animal)

派生类可以为继承自父类的方法提供自己的实现(重写)。使用 super 关键字调用父类的方法(super.methodName())或父类构造函数(在派生类构造函数内部使用 super())。

标记为 abstract 的类不能直接实例化。它们通常用作基类,并且可能包含 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"); // 派生类中的构造函数必须调用 super()
}
printMeeting(): void {
console.log("The Accounting Department meets each Monday at 10am.");
}
}
// const dept = new Department("General"); // 错误: Cannot create an instance of an abstract class. (无法创建抽象类的实例)
const accounting = new AccountingDepartment();
accounting.printName();
accounting.printMeeting();

类可以使用 implements 关键字实现一个或多个接口。这强制类必须遵守接口定义的结构。

interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class DigitalClock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date): void {
this.currentTime = d;
}
}
const clock = new DigitalClock();
console.log(clock.currentTime);