JSDoc tag

@enum

  • Checked by TypeScript
  • Tested with TypeScript 5.9

@enum {T} above an object literal tells TypeScript that every property of the object has type T. A member of another type is an error, and the object's name becomes a type you can use in @param and @type.

It is not a TypeScript enum. The type named by an @enum {string} object is just string, so any string passes where that type is expected, not only the member values. For a closed set of values, use a const object and a union of its values, shown in the last example.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
An object of constants /** @enum {string} */ const Status = { Draft: "draft", Live: "live" }; const Status: Record<string, string> = { Draft: "draft", Live: "live" };
Using it as a type /** @param {Status} status */ function f(status: string) {}
A closed set of values const Status = /** @type {const} */ ({ … }); /** @typedef {(typeof Status)[keyof typeof Status]} StatusValue */ const Status = { … } as const; type StatusValue = (typeof Status)[keyof typeof Status];

Examples

status.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. status.js(9,12): error TS2749: 'Status' refers to a value, but is being used as a type here. Did you mean 'typeof Status'? checked 21 October 2026
/** @enum {string} */
export const Status = {
  Draft: "draft",
  Live: "live",
  Archived: "archived",
};

/**
 * @param {Status} status
 * @returns {boolean}
 */
export function isVisible(status) {
  return status === Status.Live;
}

isVisible(Status.Draft);
An object of constants with @enum.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
status.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: status.js(6,3): error TS2322: Type 'string' is not assignable to type 'number'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. status.js(6,3): error TS2322: Type 'string' is not assignable to type 'number'. 7.0.2 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. No errors. checked 21 October 2026
/** @enum {number} */
export const Priority = {
  Low: 1,
  Normal: 2,
  High: "3",error TS2322: Type 'string' is not assignable to type 'number'.
};
Every member must have the @enum type.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
status.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. status.js(7,13): error TS2749: 'Status' refers to a value, but is being used as a type here. Did you mean 'typeof Status'? checked 21 October 2026
/** @enum {string} */
export const Status = {
  Draft: "draft",
  Live: "live",
};

/** @param {Status} status */
export function setStatus(status) {
  return status;
}

// Status means string here, so a value that is not in the enum still passes.
setStatus("deleted");
An @enum type accepts any value of its member type.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
status.js status.ts Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: status.js(15,11): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'. status.ts(14,11): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. status.js(15,11): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'. status.ts(14,11): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. status.js(15,11): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'. status.ts(14,11): error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'. checked 21 October 2026
export const Status = /** @type {const} */ ({
  Draft: "draft",
  Live: "live",
});

/** @typedef {(typeof Status)[keyof typeof Status]} StatusValue */

/** @param {StatusValue} status */
export function setStatus(status) {
  return status;
}

setStatus(Status.Live);
setStatus("deleted");error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'.
export const Status = {
  Draft: "draft",
  Live: "live",
} as const;

type StatusValue = (typeof Status)[keyof typeof Status];

export function setStatus(status: StatusValue) {
  return status;
}

setStatus(Status.Live);
setStatus("deleted");error TS2345: Argument of type '"deleted"' is not assignable to parameter of type 'StatusValue'.
For a closed set of values, use a const object and a union.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What the tag checks

The tag checks the members: each value must be assignable to the type in the braces, so High: "3" in an @enum {number} is TS2322. The members can have any type, not only strings and numbers; @enum {(n: number) => number} declares an object of functions.

Put the tag directly above the declaration whose value is the object literal, as in the examples.

Using the name as a type

@param {Status} status means status has the member type, string. The third example passes "deleted", which is not one of the values, and tsc accepts it. That is TypeScript's documented behavior for @enum, and the main difference from a TypeScript enum.

When only the listed values should be allowed, make the object a const assertion and declare the union of its values with @typedef {(typeof Status)[keyof typeof Status]} StatusValue. The call with "deleted" then fails with TS2345.

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.

@enum no longer declares a type

TypeScript 7.0 · JSDoc and JavaScript patterns 7.0 no longer reads

The pattern: An object marked @enum and its name used as a type (@param {Status} status), or relied on to check its values.

Why: The port's list of changes drops Closure-only JSDoc, @enum among it: the tag is ordinary, so the object's name used as a type is a value used as a type (TS2749), and the values are no longer checked against the @enum type (the TS2322 5.9 reported is gone). Source: CHANGES.md: Values are no longer resolved as types in JSDoc type positions.

An object of constants with @enum status.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
status.js(9,12): error TS2749: 'Status' refers to a value, but is being used as a type here. Did you mean 'typeof Status'?

Every member must have the @enum type status.js

TypeScript 5.9.3
status.js(6,3): error TS2322: Type 'string' is not assignable to type 'number'.
TypeScript 6.0.3same as 5.9.3

The same errors as 5.9.3.

TypeScript 7.0.2differs from 5.9.3

No errors.

An @enum type accepts any value of its member type status.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
status.js(7,13): error TS2749: 'Status' refers to a value, but is being used as a type here. Did you mean 'typeof Status'?

What works in every version: A const object with @type {const} and a @typedef of its values, which checks the values more tightly in every version.

The example For a closed set of values, use a const object and a union on this page shows it, with the same result under every version.

Gotchas

  • The enum keyword is TypeScript syntax and an error in a .js file (TS8006).
  • Members of an @enum object are not read-only: Status.Live = "x" passes. The const assertion version makes them read-only as well.
  • Object.values(Status) is typed as string[] for an @enum {string} object and as a union of the literals for the const version.
  • TypeScript 7.0 gives @enum no meaning, so the object's name used as a type is TS2749 there; the section Under TypeScript 6.0 and 7.0 shows what 7.0.2 reports for each example above. The const object with a union @typedef of its values works in every version.

Questions

How do I write an enum in JavaScript with JSDoc?

For a set of named constants, an object with @enum {string} or @enum {number}. If the type should accept only those values, use /** @type {const} */ on the object and a @typedef for the union of its values; that is the closer match to a TypeScript string enum.

Sources

Last reviewed 21 October 2026.