TypeScript error

TS18013: A #private field read from outside its class

  • Error TS18013
  • Tested with TypeScript 5.9

A field whose name starts with # is private in JavaScript itself: code outside the class body cannot even name it, and engines reject such code when they parse it. TypeScript reports the same mistake as TS18013 before the code runs.

Unlike @private, which only TypeScript enforces (TS2341), a # field stays private at run time too.

At a glance

CodeTS18013
MessageProperty '{0}' is not accessible outside class '{1}' because it has a private identifier.
TypeScript's categoryerror
Listed underClasses, JSX and unused code
Turned on by No option: every checked file reports it
In .js files Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file

The message is TypeScript's own text from its diagnostic messages file (Apache-2.0); {0} and {1} are filled in by tsc for each error.

What it looks like

account.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: account.js(13,21): error TS18013: Property '#balance' is not accessible outside class 'Account' because it has a private identifier. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. account.js(13,21): error TS18013: Property '#balance' is not accessible outside class 'Account' because it has a private identifier. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. account.js(13,21): error TS18013: Property '#balance' is not accessible outside class 'Account' because it has a private identifier. checked 21 October 2026
export class Account {
  #balance = 0;

  /** @param {number} cents */
  deposit(cents) {
    this.#balance += cents;
  }
}

const account = new Account();
account.deposit(500);
console.log(account.#balance);error TS18013: Property '#balance' is not accessible outside class 'Account' because it has a private identifier.
A #private field read from outside its class.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["**/*.js"]
}

What causes it

  • Reading or writing object.#field outside the class that declares it, often in a test or a helper.

How to fix it

Expose what callers need

Add a getter or a method on the class, as the fixed example does with balance, and keep the field itself private.

account.js TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
export class Account {
  #balance = 0;

  /** @param {number} cents */
  deposit(cents) {
    this.#balance += cents;
  }

  get balance() {
    return this.#balance;
  }
}

const account = new Account();
account.deposit(500);
console.log(account.balance);
A getter that exposes what outside code may read.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["**/*.js"]
}

Gotchas

  • Code inside the class can read the field on any instance of it, not only this, which is how methods such as equals(other) work.

Sources

Last reviewed 21 October 2026.