讲解

TypeScript 的类在 JavaScript 类的基础上增加了四样能力:字段声明、访问修饰符、implements 接口检查、抽象类。字段声明要求在类体里先声明字段再使用(strictPropertyInitialization 下,字段必须在构造函数里被赋值,否则编译报错——这是严格模式里最常见的报错之一)。如果字段确实由框架注入或在异步方法里才赋值,可以用显式赋值断言 name!: string 告诉编译器「我保证它会赋值」。

三个访问修饰符:public(默认,到处可用)、private(仅本类内部)、protected(本类及子类)。要清醒地认识到:这些修饰符只在编译期有效,编译产物里荡然无存,运行时用 obj.anything 照样访问得到。真正的运行时私有是 JavaScript 的 #field 语法(ES2022 标准),TypeScript 也支持——两者可以混用,# 私有更硬,private 更灵活(测试、框架反射需要时能绕开)。

抽象类(abstract class)不能被实例化,里面的抽象方法只有签名没有实现,由子类必须实现——适合「模板方法」式的框架设计。配合 readonly 字段、参数属性(constructor(private name: string) 一步完成声明+赋值,示例里会用到),类的表达力相当完整。

示例

字段、修饰符与参数属性:

class BankAccount {
  readonly accountNo: string;
  private balance: number;

  constructor(accountNo: string, initial: number = 0) {
    this.accountNo = accountNo;
    this.balance = initial;
  }

  deposit(amount: number): void {
    this.balance += amount;
  }

  getBalance(): number {
    return this.balance;
  }
}

const acc = new BankAccount("A-001", 100);
acc.deposit(50);
// acc.balance = 0; // 若取消注释:private,编译报错
console.log(`${acc.accountNo} 余额:${acc.getBalance()}`);

参数属性简写与 implements:

interface Named {
  fullName(): string;
}

class Person implements Named {
  constructor(
    public firstName: string,
    public lastName: string,
  ) {}

  fullName(): string {
    return `${this.lastName}${this.firstName}`;
  }
}

const p = new Person("三", "张");
console.log(p.fullName());

抽象类定义骨架,子类填充细节:

abstract class Exporter {
  constructor(protected data: string[]) {}

  abstract render(): string; // 子类必须实现

  export(): string {
    return `=== 导出开始 ===\n${this.render()}\n=== 导出结束 ===`;
  }
}

class CsvExporter extends Exporter {
  render(): string {
    return this.data.join(",");
  }
}

const exporter = new CsvExporter(["书名", "作者", "年份"]);
console.log(exporter.export());

常见坑

  • strictPropertyInitialization 报错就乱加 !:赋值断言是承诺不是修复,确实「构造函数保证赋值」之外的场景,优先考虑给默认值或标可选。
  • 以为 private 是运行时隔离:它只是编译期约定;要硬隔离用 #field。两者命名别冲突。
  • 在构造函数里调用可覆写方法:子类字段尚未初始化,多态调用会拿到 undefined——构造函数里只做纯赋值。
  • 抽象类当接口用:只含方法签名的「纯抽象类」应改成 interface;抽象类的价值在于能携带共享实现。

小结

类新增字段声明、public/private/protected、implements 检查与抽象类;修饰符是编译期约定,运行时私有靠 #field;参数属性让构造函数更简洁。下一章进入 TypeScript 最强大的特性:泛型。