Type expression

Object shapes

  • Collections
  • Tested with TypeScript 5.9

An object type lists the properties a value must have, each with its type: {{ street: string, city: string, unit?: string }}. The outer braces belong to the JSDoc tag and the inner ones to the type, which is why object types in JSDoc start with {{.

A ? after the name makes a property optional. Commas and semicolons both separate properties; TypeScript prints semicolons in its messages.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
Inline /** @param {{ street: string, city: string }} address */ (address: { street: string; city: string })
Optional property {{ unit?: string }} { unit?: string }
Named /** @typedef {{ street: string, city: string }} Address */ type Address = { street: string; city: string };

Examples

shipping.js shipping.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
/**
 * @param {{ street: string, city: string, unit?: string }} address
 * @param {{ express: boolean; giftWrap?: boolean }} [options]
 */
export function shippingLabel(address, options) {
  const speed = options?.express ? "EXPRESS" : "STANDARD";
  return [address.unit, address.street, address.city, speed].filter(Boolean).join("\n");
}

shippingLabel({ street: "12 Market St", city: "Springfield" });
shippingLabel({ street: "12 Market St", city: "Springfield", unit: "4B" }, { express: true });
export function shippingLabel(
  address: { street: string; city: string; unit?: string },
  options?: { express: boolean; giftWrap?: boolean },
) {
  const speed = options?.express ? "EXPRESS" : "STANDARD";
  return [address.unit, address.street, address.city, speed].filter(Boolean).join("\n");
}

shippingLabel({ street: "12 Market St", city: "Springfield" });
shippingLabel({ street: "12 Market St", city: "Springfield", unit: "4B" }, { express: true });
An object type written inline.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
shipping.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: shipping.js(7,62): error TS2353: Object literal may only specify known properties, and 'unti' does not exist in type '{ street: string; city: string; unit?: string | undefined; }'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. shipping.js(7,62): error TS2353: Object literal may only specify known properties, and 'unti' does not exist in type '{ street: string; city: string; unit?: string | undefined; }'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. shipping.js(7,62): error TS2353: Object literal may only specify known properties, and 'unti' does not exist in type '{ street: string; city: string; unit?: string | undefined; }'. checked 21 October 2026
/** @param {{ street: string, city: string, unit?: string }} address */
export function shippingLabel(address) {
  return `${address.street}, ${address.city}`;
}

shippingLabel({ street: "12 Market St", city: "Springfield", unti: "4B" });error TS2353: Object literal may only specify known properties, and 'unti' does not exist in type '{ street: string; city: string; unit?: string | undefined; }'.
A misspelled property in an object literal.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
shipping.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: shipping.js(2,43): error TS1247: A type literal property cannot have an initializer. shipping.js(2,44): error TS1109: Expression expected. shipping.js(4,7): error TS2741: Property 'unit' is missing in type '{ street: string; }' but required in type '{ street: string; unit: string; }'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. shipping.js(2,43): error TS1247: A type literal property cannot have an initializer. shipping.js(2,44): error TS1109: Expression expected. shipping.js(4,7): error TS2741: Property 'unit' is missing in type '{ street: string; }' but required in type '{ street: string; unit: string; }'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. shipping.js(2,43): error TS1247: A type literal property cannot have an initializer. shipping.js(2,44): error TS1109: Expression expected. shipping.js(4,7): error TS2741: Property 'unit' is missing in type '{ street: string; }' but required in type '{ street: string; unit: string; }'. checked 21 October 2026
/** @type {{ street: string, unit: string= }} */error TS1247: A type literal property cannot have an initializer.error TS1109: Expression expected.
const address = { street: "12 Market St" };error TS2741: Property 'unit' is missing in type '{ street: string; }' but required in type '{ street: string; unit: string; }'.

export { address };
A postfix = does not make a property optional.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Misspelled properties

When you pass an object literal straight to a parameter, TypeScript rejects properties the type does not have. unti: "4B" instead of unit is TS2353 ("Object literal may only specify known properties"), as the second example shows. The check applies to fresh literals only; an object stored in a variable first may carry extra properties.

The postfix = is not optional

Older JSDoc marks an optional property with = after its type: unit: string=. TypeScript does not support that form inside object types. TypeScript 5.9 reports a syntax error in the comment (TS1247 and TS1109) and then treats the property as required (TS2741 on the object), as the third example shows. Write unit?: string.

Inline or named?

Inline shapes are fine for one-off parameters. As soon as a shape appears twice, or is longer than one line, give it a name with @typedef; the name shows in hovers and error messages instead of the whole shape.

Gotchas

  • Methods can be written as properties with function types, {{ save: (draft: string) => void }}, or in method form, {{ save(draft: string): void }}.
  • With exactOptionalPropertyTypes, an optional property cannot be set to undefined explicitly; without it, unit: undefined is allowed.

Questions

How do I write an object type in JSDoc?

Inside the tag's braces, write the type's own braces with the properties: @param {{ id: string, tags?: string[] }} item.

Sources

Last reviewed 20 October 2026.