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
| Code | TS18013 |
|---|---|
| Message | Property '{0}' is not accessible outside class '{1}' because it has a private identifier. |
| TypeScript's category | error |
| Listed under | Classes, 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.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.#fieldoutside 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);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 asequals(other)work.
Sources
- Classes: private members · TypeScript handbook
- Private properties · MDN Web Docs
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 21 October 2026.