JSDoc tag

@class and @constructor

  • Checked by TypeScript
  • Tested with TypeScript 5.9
  • Alias @constructor

@class and its alias @constructor tell TypeScript that a function is meant to be called with new. TypeScript then treats it like a class: this.name = name declares a property, methods added through Counter.prototype see the right this, and calling the function without new is an error (TS2348).

The tag is for code written before class syntax, or code that keeps the constructor-function style. In a new file, a class gives the same checking without a tag.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
A constructor function /** * @constructor * @param {string} name */ function Counter(name) { this.name = name; } class Counter { name: string; constructor(name: string) { this.name = name; } }

Examples

counter.js counter.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 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. counter.js(6,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. counter.js(7,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. counter.js(16,16): error TS7009: 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type. checked 21 October 2026
/**
 * @constructor
 * @param {string} name
 */
export function Counter(name) {
  this.name = name;
  this.count = 0;
}

/** @returns {number} */
Counter.prototype.increment = function () {
  this.count += 1;
  return this.count;
};

const visits = new Counter("visits");
visits.increment();
export class Counter {
  name: string;
  count: number;

  constructor(name: string) {
    this.name = name;
    this.count = 0;
  }

  increment(): number {
    this.count += 1;
    return this.count;
  }
}

const visits = new Counter("visits");
visits.increment();
A constructor function marked with @constructor.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
counter.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: counter.js(11,16): error TS2348: Value of type 'typeof Counter' is not callable. Did you mean to include 'new'? 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. counter.js(11,16): error TS2348: Value of type 'typeof Counter' is not callable. Did you mean to include 'new'? 7.0.2 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. counter.js(6,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. counter.js(7,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. checked 21 October 2026
/**
 * @constructor
 * @param {string} name
 */
export function Counter(name) {
  this.name = name;
  this.count = 0;
}

const visits = Counter("visits");error TS2348: Value of type 'typeof Counter' is not callable. Did you mean to include 'new'?

export { visits };
Calling a @constructor function without new.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
counter.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 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. counter.js(3,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. counter.js(4,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. checked 21 October 2026
/** @param {string} name */
export function Counter(name) {
  this.name = name;
  this.count = 0;
}

// No error here: without @constructor, TypeScript lets the function be called directly too.
const visits = Counter("visits");

export { visits };
The same function without @constructor: the missing new goes unnoticed.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What the tag changes

TypeScript already treats a function that assigns to this as a constructor, so properties and new Counter() work without the tag. What @constructor adds is the other half of the check: the function can no longer be called directly. The second and third examples are the same code with and without the tag, and only the tagged one rejects Counter("visits").

Put the constructor's @param tags in the same comment. Methods assigned to Counter.prototype can take their own JSDoc comment with @param and @returns.

Classes instead

A class declaration needs no tag: calling a class without new is already an error at run time and in the checker, and fields, static members, #private fields and extends all work in .js files. The TypeScript tab on the first example shows the class form.

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. Three of them report something different from 5.9.3, the version the page describes; the ✗ on their badges link to their entries 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.

A constructor function marked with @constructor counter.js

TypeScript 5.9.3

No errors.

TypeScript 6.0.3same as 5.9.3

No errors.

TypeScript 7.0.2differs from 5.9.3
counter.js(6,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
counter.js(7,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
counter.js(16,16): error TS7009: 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.

Calling a @constructor function without new counter.js

TypeScript 5.9.3
counter.js(11,16): error TS2348: Value of type 'typeof Counter' is not callable. Did you mean to include 'new'?
TypeScript 6.0.3same as 5.9.3

The same errors as 5.9.3.

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

The same function without @constructor: the missing new goes unnoticed counter.js

TypeScript 5.9.3

No errors.

TypeScript 6.0.3same as 5.9.3

No errors.

TypeScript 7.0.2differs from 5.9.3
counter.js(3,3): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
counter.js(4,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

  • A function that is meant to work both with and without new (the way Date and Array do) cannot use @constructor, because the tag forbids the plain call.
  • @public, @private and @protected misfire in constructor functions: TypeScript 5.9 reports the private property as inaccessible on the line that declares it, inside the constructor. Use a class if you need access modifiers.
  • TypeScript reports constructor-function errors only in checked files (checkJs or // @ts-check).
  • TypeScript 7.0 no longer treats a @class or @constructor function as a constructor, and no longer follows prototype assignments; the section Under TypeScript 6.0 and 7.0 shows what 7.0.2 reports for each example above. A class declaration is checked the same way in every version.

Questions

What is the difference between @class and @constructor?

None for TypeScript: both names produce the same tag. In the JSDoc documentation tool they are also synonyms.

Sources

Last reviewed 21 October 2026.