JSDoc tag

@private

  • Checked by TypeScript
  • Since TypeScript 3.8

@private on a class member limits it to code inside that class. Since TypeScript 3.8, a use from outside, including from a subclass, is an error (TS2341, "Property 'balance' is private and only accessible within class 'Account'"). It is the JavaScript spelling of TypeScript's private modifier.

Like private, the tag is a compile-time check only. The property is an ordinary property at run time, visible to Object.keys and to any code that ignores the types. A #private field is private at run time as well and needs no tag.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
A private property /** @private */ balance = 0; private balance = 0;
Private at run time too #balance = 0; #balance = 0;

Examples

account.js account.ts Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: account.js(15,9): error TS2341: Property 'balance' is private and only accessible within class 'Account'. account.ts(13,9): error TS2341: Property 'balance' is private and only accessible within class 'Account'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. account.js(15,9): error TS2341: Property 'balance' is private and only accessible within class 'Account'. account.ts(13,9): error TS2341: Property 'balance' is private and only accessible within class 'Account'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. account.js(15,9): error TS2341: Property 'balance' is private and only accessible within class 'Account'. account.ts(13,9): error TS2341: Property 'balance' is private and only accessible within class 'Account'. checked 21 October 2026
export class Account {
  /** @private */
  balance = 0;

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

const account = new Account();
account.deposit(20);
account.balance = 1000000;error TS2341: Property 'balance' is private and only accessible within class 'Account'.
export class Account {
  private balance = 0;

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

const account = new Account();
account.deposit(20);
account.balance = 1000000;error TS2341: Property 'balance' is private and only accessible within class 'Account'.
A @private property, used outside its class.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
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} amount */
  deposit(amount) {
    this.#balance += amount;
    return this.#balance;
  }

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

const account = new Account();
account.deposit(20);
account.balance;
A #private field, private at run time too.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
account.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: account.js(5,8): error TS2341: Property 'balance' is private and only accessible within class 'Account'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. account.js(5,8): error TS2341: Property 'balance' is private and only accessible within class 'Account'. 7.0.2 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. account.js(5,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. checked 21 October 2026
/** @constructor */
export function Account() {
  /** @private */
  this.balance = 0;error TS2341: Property 'balance' is private and only accessible within class 'Account'.
}
@private in a constructor function reports the wrong line.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

@private or a #private field?

A #balance field cannot be read from outside the class at all, by any code, so it is the stronger choice for real encapsulation. The @private tag fits code that must keep a plain property name: properties read by serialization, tests that peek on purpose, or older code where renaming would break callers.

An accessibility tag on a # field is an error (TS18010), since the field is already private.

Not in constructor functions

The handbook says the accessibility tags do not work in constructor functions, and the third example shows what happens: TypeScript 5.9 reports TS2341 on the line inside the constructor that creates the property, the one place it should be allowed. Convert the function to a class before adding @private.

Under TypeScript 6.0 and 7.0

Every example on this page also runs under TypeScript 6.0.3 and 7.0.2 when this site is built. One of them reports something different from 5.9.3, the version the page describes; the ✗ on its badge links to its entry below.

Constructor functions are not classes

TypeScript 7.0 · JSDoc and JavaScript patterns 7.0 no longer reads

The pattern: A function that sets this.name = … and is called with new, with or without @class or @constructor, and methods added through prototype.

Why: The port's list of changes says constructor functions are no longer supported and @class or @constructor no longer makes a function a constructor. So this in the function is untyped (TS2683 under strict), new on it is untyped (TS7009), and the checks that came with the class (TS2348 for a call without new, TS2341 for a @private property) are gone. Source: CHANGES.md: Constructor functions are no longer supported.

@private in a constructor function reports the wrong line account.js

TypeScript 5.9.3
account.js(5,8): error TS2341: Property 'balance' is private and only accessible within class 'Account'.
TypeScript 6.0.3same as 5.9.3

The same errors as 5.9.3.

TypeScript 7.0.2differs from 5.9.3
account.js(5,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

What works in every version: Write a class, with fields and methods in its body.

cart.js cart.ts 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
/** @typedef {{ sku: string, quantity: number }} Line */

export class Cart {
  /** @type {Line[]} */
  items = [];

  /** @type {string | null} */
  coupon = null;

  /**
   * @param {string} currency ISO code, such as "USD".
   */
  constructor(currency) {
    this.currency = currency;
  }

  /**
   * @param {string} sku
   * @param {number} [quantity]
   */
  add(sku, quantity = 1) {
    this.items.push({ sku, quantity });
    return this;
  }
}

const cart = new Cart("USD").add("LAMP-01").add("DESK-02", 2);
console.log(cart.currency.toLowerCase(), cart.items.length, cart.coupon?.trim());
type Line = { sku: string; quantity: number };

export class Cart {
  items: Line[] = [];

  coupon: string | null = null;

  currency: string;

  constructor(currency: string) {
    this.currency = currency;
  }

  add(sku: string, quantity = 1): this {
    this.items.push({ sku, quantity });
    return this;
  }
}

const cart = new Cart("USD").add("LAMP-01").add("DESK-02", 2);
console.log(cart.currency.toLowerCase(), cart.items.length, cart.coupon?.trim());
Fields with initializers, a field set in the constructor, a typed empty array.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Gotchas

  • The private keyword is TypeScript syntax; in a .js file it is an error (TS8009).
  • @private also blocks subclasses. For members subclasses may use, write @protected.

Questions

Does @private make a property private at run time?

No. It only changes what TypeScript allows. Use a #private field when the value must be hidden at run time.

Sources

Last reviewed 20 October 2026.