Skip to content

访问修饰符

TypeScript 中的类结构主要包含属性、构造函数、方法、存取器、访问修饰符、装饰器等。我们可以像声明变量和函数一样,为这些成员添加类型标注。

访问权限对比

TypeScript 提供了三种访问修饰符(publicprotectedprivate)以及 ES2022 的私有字段(#),用于控制类成员的可访问性。

修饰符含义类内部子类实例对象备注
public公开默认值。如果不加修饰符,默认为 public。
protected受保护只能在类及其子类中访问。
private私有仅限类内部访问。TS 编译后会消失。
#私有字段ES2022 标准。运行时真正的私有,编译后保留。

代码演示

typescript
class Animal {
  // ES2022 私有字段
  #type: string;

  constructor(
    public name: string, // public: 随处可访问
    protected color: string, // protected: 仅类和子类可访问
    private _age: number, // private: 仅类内部可访问 (TS检查)
    type: string,
  ) {
    this.#type = type;
  }

  show() {
    console.log(`Name: ${this.name}, Color: ${this.color}, Age: ${this._age}`);
    // 类内部可以访问所有修饰符修饰的成员
  }
}

class Cat extends Animal {
  info() {
    // ✅ public: 子类可访问
    console.log(this.name);

    // ✅ protected: 子类可访问
    console.log(this.color);

    // ❌ private: 子类不可访问
    // console.log(this._age); // Error: Property '_age' is private...

    // ❌ #private: 子类不可访问
    // console.log(this.#type); // Error: Property '#type' is not accessible...
  }
}

const a = new Animal('小白', '白色', 3, 'Dog');

// ✅ public: 实例可访问
console.log(a.name);
a.show();

// ❌ protected: 实例不可访问
// console.log(a.color); // Error

// ❌ private: 实例不可访问
// console.log(a._age); // Error

构造函数参数属性(简写)

TypeScript 提供了一种简写语法,可以在构造函数的参数前直接添加访问修饰符(publicprivateprotected),从而自动声明同名属性并完成赋值。

写法对比

typescript
// 普通写法
class Point {
  public x: number;
  public y: number;
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}
typescript
// 简写形式
class Point {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

注意:目前 # 私有字段不支持在构造函数中通过简写形式声明。

常见问题与注意事项

1. 属性初始化检查

strict: true 模式下,TypeScript 会默认开启 strictPropertyInitialization,要求类的非可选属性必须在构造函数中初始化。

解决方案

如果不想在构造函数中初始化,可以使用非空断言操作符 ! 或配置 tsconfig.json

typescript
class User {
  name!: string; // 告诉 TS 我稍后会初始化它
}

或者关闭配置:

json
{
  "compilerOptions": {
    "strictPropertyInitialization": false
  }
}

2. private vs #

  • private:TypeScript 的语法糖。在编译成 JavaScript 后,private 修饰符会被移除,运行时代码中该属性实际上是公开的(虽然 TS 编译器会报错,但在 JS 运行时可以通过 (a as any)._age 访问)。
  • #:ES2022 的标准特性。编译后依然保留(或通过 WeakMap polyfill),在运行时提供真正的私有性,无法从外部访问。