Sửa lỗi: Thuộc tính không thể truy cập vì có định danh private (TS18013)

intermediate🔵 TypeScript2026-07-13| TypeScript 3.8+, Node.js, Trình duyệt hiện đại (ES2020+)

Error Message

Property '#field' is not accessible outside class 'X' because it has a private identifier. (TS18013)
#typescript#javascript#oop#web-development

Tại sao lỗi này xảy ra

Có thể bạn đang gặp lỗi này vì đang sử dụng ECMAScript Private Fields (tiền tố #). Khác với từ khóa private tiêu chuẩn trong TypeScript, cú pháp # thực thi "bảo mật cứng" (hard privacy). Điều này có nghĩa là chính JavaScript engine sẽ chặn truy cập ngay tại thời điểm thực thi (runtime).

Các nguyên nhân phổ biến gây ra lỗi TS18013 bao gồm:

  • Truy cập #field từ một instance bên ngoài định nghĩa class.
  • Cố gắng đọc #field của class cha từ một class con (subclass).
  • Cố gắng vượt qua cơ chế bảo mật bằng (obj as any).#field, dẫn đến lỗi cú pháp.

Giải pháp 1: Hiển thị dữ liệu thông qua Getter

Cách sửa lỗi đáng tin cậy nhất là định nghĩa một getter công khai (public). Cách này giúp bảo vệ trạng thái nội bộ trong khi vẫn cung cấp một "cửa sổ" được kiểm soát để mã bên ngoài có thể đọc giá trị.

class User {
  #apiToken: string;

  constructor(token: string) {
    this.#apiToken = token;
  }

  // Cung cấp chế độ xem chỉ đọc cho dữ liệu
  get maskedToken(): string {
    return `${this.#apiToken.substring(0, 4)}****`;
  }
}

const admin = new User("secret_9921_token");
// console.log(admin.#apiToken); // Lỗi TS18013
console.log(admin.maskedToken); // Hoạt động: "secr****"

Giải pháp 2: Sử dụng từ khóa 'private' cho bảo mật "mềm"

Nếu bạn chỉ cần ngăn chặn việc sử dụng vô ý nhưng muốn giữ cho mã linh hoạt để unit test, hãy thay thế # bằng từ khóa private. private của TypeScript là bảo mật "mềm" — nó kiểm tra lỗi trong quá trình phát triển nhưng sẽ biến mất sau khi mã được biên dịch sang JavaScript.

class Config {
  // Sử dụng 'private' thay vì '#'
  private port: number = 8080;

  public getUrl() {
    return `http://localhost:${this.port}`;
  }
}

const cfg = new Config();
// cfg.port; // Lỗi TS, nhưng ít khắt khe hơn #

Giải pháp 3: Chuyển sang 'protected' cho các class con

Các định danh private (#) hoàn toàn ẩn đối với các class con. Nếu một subclass cần truy cập một thuộc tính từ class cha, bạn phải sử dụng từ khóa protected. Lưu ý rằng protected không hoạt động với ký hiệu #.

class Parent {
  // #internalValue = 10; // Các class con không thể thấy thuộc tính này
  protected sharedValue = 10; // Các class con CÓ THỂ thấy thuộc tính này
}

class Child extends Parent {
  logValue() {
    console.log(this.sharedValue); // Thành công
  }
}

Giải pháp 4: Di chuyển Logic vào trong Class

Đôi khi lỗi này là một gợi ý cho thấy thiết kế class của bạn đang bị "rò rỉ". Thay vì lấy dữ liệu ra ngoài để xử lý, hãy chuyển logic đó vào một method bên trong class. Điều này tuân theo nguyên tắc "Tell, Don't Ask" (Hãy ra lệnh, đừng hỏi) của lập trình hướng đối tượng.

// Nên tránh: Can thiệp sâu vào bên trong class
// if (account.#balance > 100) { ... }

// Tốt hơn: Để class tự quản lý trạng thái của chính nó
class Account {
  #balance: number = 500;

  public canAfford(amount: number): boolean {
    return this.#balance >= amount;
  }
}

So sánh nhanh: # và private

  Tính năng
  Định danh #
  Từ khóa private




  Mức độ bảo mật
  Cứng (Runtime)
  Mềm (Compile-time)


  Truy cập từ Class con
  Không
  Không (Dùng protected)


  Vượt qua bằng 'any'
  Không thể
  Có thể


  Kết quả JavaScript
  Giữ nguyên là #field
  Trở thành thuộc tính bình thường

Xác minh và kiểm tra

Để đảm bảo lỗi đã hết, hãy chạy npx tsc để kích hoạt kiểm tra kiểu toàn diện. Nếu bạn đã triển khai một getter hoặc thay đổi phạm vi truy cập thành private, IDE của bạn (như VS Code) sẽ ngay lập tức ngừng hiển thị gạch chân đỏ. Để xác minh lúc runtime, hãy kiểm tra console trình duyệt — việc truy cập các trường # từ bên ngoài sẽ ném ra lỗi SyntaxError ngay cả trước khi mã chạy.

Mẹo chuyên nghiệp

  • Sử dụng # cho các thành phần nội bộ của thư viện khi bạn cần ngăn chặn tuyệt đối người dùng chạm vào các trạng thái nhạy cảm.
  • Ưu tiên dùng private cho phát triển ứng dụng thông thường; nó giúp việc viết unit test dễ dàng hơn đáng kể.
  • Hãy nhớ rằng các trường # có tốc độ thực thi chậm hơn một chút trên các engine JS cũ, mặc dù V8 hiện đại (Chrome/Node.js) đã tối ưu hóa chúng rất tốt.

Related Error Notes