{
  "types": [
    {
      "id": "primitives",
      "slug": "primitives",
      "title": "Primitive types",
      "category": "Basics",
      "jsdoc": "{string}",
      "typescript": "string",
      "syntax": [
        {
          "use": "Text",
          "jsdoc": "/** @type {string} */",
          "typescript": ": string"
        },
        {
          "use": "Numbers",
          "jsdoc": "/** @type {number} */",
          "typescript": ": number"
        },
        {
          "use": "True or false",
          "jsdoc": "/** @type {boolean} */",
          "typescript": ": boolean"
        },
        {
          "use": "Big integers",
          "jsdoc": "/** @type {bigint} */",
          "typescript": ": bigint"
        },
        {
          "use": "Symbols",
          "jsdoc": "/** @type {symbol} */",
          "typescript": ": symbol"
        }
      ],
      "since": null,
      "summary": "The primitive types in JSDoc are string, number, boolean, bigint and symbol, written in lowercase as in TypeScript. Examples, and the capital-letter trap.",
      "intro": [
        "JavaScript's primitive values each have a type with the same name in lowercase: `string`, `number`, `boolean`, `bigint` and `symbol`, plus `null` and `undefined`, which have [their own page](/types/null-and-undefined/). Inside JSDoc braces you write them exactly as in a `.ts` file: `@type {string}`, `@param {number} price`.",
        "There is no separate integer or float type: `number` covers both, as it does at run time. For whole numbers beyond `Number.MAX_SAFE_INTEGER`, use `bigint` and the `n` suffix."
      ],
      "examples": [
        "types/primitives-basic",
        "types/primitives-mismatch",
        "types/primitives-wrapper"
      ],
      "sections": [
        {
          "id": "lowercase",
          "heading": "Lowercase, not capitalized",
          "body": [
            "`String`, `Number` and `Boolean` with a capital letter are the wrapper object types, the type of `new String(\"x\")`. In a `.js` file TypeScript reads `{String}`, `{Number}` and `{Boolean}` in JSDoc as the lowercase types, but `new String(…)` still creates a wrapper object, which is not a `string`: the third example assigns a `new String(…)` to a `string` and gets TS2322 with the hint \"'string' is a primitive, but 'String' is a wrapper object\". Write the lowercase names."
          ]
        },
        {
          "id": "values-from-outside",
          "heading": "Values from forms and URLs",
          "body": [
            "Input fields, query strings and `localStorage` give you strings. Passing one where a `number` is expected is the mistake the second example catches (TS2345). Convert at the boundary with `Number(…)` or `parseInt(…, 10)` and check the result with `Number.isFinite` before using it."
          ]
        }
      ],
      "gotchas": [
        "A `number` parameter accepts `Infinity` and the not-a-number value; the type cannot rule them out, so check with `Number.isFinite` where it matters.",
        "Template literals and `+` with a string produce strings, so `price + \"\"` has type `string`, not `number`.",
        "Without `strict`, `null` and `undefined` are assignable to every primitive type."
      ],
      "faq": [
        {
          "q": "Should I write {String} or {string} in JSDoc?",
          "a": "`{string}`. In a `.js` file TypeScript reads `{String}` as `string` too, but in a `.ts` file `String` is the wrapper object type, and TypeScript's own messages and the handbook use the lowercase names."
        }
      ],
      "related": [
        "types/literal-types",
        "types/union",
        "tags/type",
        "tags/param"
      ],
      "sources": [
        {
          "title": "Everyday Types: the primitives",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Primitive",
          "url": "https://developer.mozilla.org/en-US/docs/Glossary/Primitive",
          "publisher": "MDN"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "literal-types",
      "slug": "literal-types",
      "title": "Literal types",
      "category": "Basics",
      "jsdoc": "{\"GET\" | \"POST\"}",
      "typescript": "\"GET\" | \"POST\"",
      "syntax": [
        {
          "use": "String literals",
          "jsdoc": "/** @param {\"GET\" | \"POST\"} method */",
          "typescript": "(method: \"GET\" | \"POST\")"
        },
        {
          "use": "Number literals",
          "jsdoc": "/** @typedef {1 | 2 | 3 | 4 | 5} Stars */",
          "typescript": "type Stars = 1 | 2 | 3 | 4 | 5;"
        },
        {
          "use": "A boolean literal",
          "jsdoc": "/** @param {true} verified */",
          "typescript": "(verified: true)"
        }
      ],
      "since": null,
      "summary": "A literal type is one exact value, such as \"GET\" or 5, used as a type. In JSDoc it goes inside the braces as in TypeScript, usually in a union of values.",
      "intro": [
        "A literal type allows exactly one value: the type `\"GET\"` accepts only the string `\"GET\"`. On their own they are rarely useful; joined into a union, `{\"GET\" | \"POST\" | \"DELETE\"}`, they list every value a parameter may take, and TypeScript rejects anything else at the call site.",
        "String, number and boolean literals all work, and editors offer the allowed strings as completions while you type the argument."
      ],
      "examples": [
        "types/literal-method",
        "types/literal-widening",
        "types/literal-numbers"
      ],
      "sections": [
        {
          "id": "widening",
          "heading": "When a value stops being a literal",
          "body": [
            "TypeScript infers a literal type for a `const` (`const fixed = \"GET\"` is `\"GET\"`), but a `let` is widened to `string`, because it could be reassigned to any string. Passing that `let` to a parameter of type `\"GET\" | \"POST\"` fails with TS2345, as the second example shows.",
            "Give the `let` the union type with `@type`, or use `const`. For object properties, which are widened the same way, a `const` assertion keeps the literals: `/** @type {const} */ ({ method: \"GET\" })`."
          ]
        },
        {
          "id": "naming",
          "heading": "Naming a set of literals",
          "body": [
            "Give a union of literals a name with `@typedef` when more than one function uses it: `/** @typedef {\"draft\" | \"live\"} Status */`. The name shows up in hovers and error messages, which reads better than the expanded union."
          ]
        }
      ],
      "gotchas": [
        "Literal types are checked only when TypeScript can see the value. Data from JSON or a form is a plain `string` until you check it against the allowed values.",
        "Template literal types extend the idea to patterns of strings, such as every string that ends in `px`."
      ],
      "faq": [
        {
          "q": "How do I restrict a JSDoc parameter to a few strings?",
          "a": "Write the allowed values as a union of string literals: `@param {\"small\" | \"medium\" | \"large\"} size`."
        }
      ],
      "related": [
        "types/union",
        "types/primitives",
        "tags/typedef",
        "tags/enum"
      ],
      "sources": [
        {
          "title": "Everyday Types: literal types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Narrowing",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "any-and-unknown",
      "slug": "any-and-unknown",
      "title": "any and unknown",
      "category": "Basics",
      "jsdoc": "{unknown}",
      "typescript": "unknown",
      "syntax": [
        {
          "use": "Anything, checked before use",
          "jsdoc": "/** @type {unknown} */",
          "typescript": ": unknown"
        },
        {
          "use": "Anything, never checked",
          "jsdoc": "/** @type {any} */",
          "typescript": ": any"
        },
        {
          "use": "Closure spellings of any",
          "jsdoc": "/** @type {*} */ or /** @type {?} */",
          "typescript": ": any"
        }
      ],
      "since": null,
      "summary": "any turns checking off for a value; unknown accepts any value but makes you check it before use. Which one to write in JSDoc, and what {*} and {?} mean.",
      "intro": [
        "Both types accept every value. The difference is what you may do with it afterwards. With `any`, TypeScript allows everything, so a misspelled property or a wrong method call passes silently. With `unknown`, TypeScript allows nothing until you narrow the value with `typeof`, `instanceof`, `in` or a type guard.",
        "Use `unknown` for values whose shape you have not checked yet: parsed JSON, `postMessage` data, caught errors. TypeScript added it in version 3.0 as the safe counterpart to `any`."
      ],
      "examples": [
        "types/unknown-narrow",
        "types/unknown-unchecked",
        "types/any-silent"
      ],
      "sections": [
        {
          "id": "closure-spellings",
          "heading": "{*} and {?}",
          "body": [
            "The Closure Compiler spellings `{*}` and `{?}` both mean `any` to TypeScript. They turn up in older JSDoc; `{*}` in particular is often meant as \"anything\" in the sense of `unknown`. Rewrite them as `unknown` when you want the check."
          ]
        },
        {
          "id": "where-any-comes-from",
          "heading": "Where any comes from without asking",
          "body": [
            "In a `.js` file, several things are `any` unless you type them: untyped parameters (reported as TS7006 under `strict`), `JSON.parse` results, empty array literals and `new Map()` without type arguments. Give the `JSON.parse` result the type `unknown` right away, as the first example does, and narrow it before use."
          ]
        }
      ],
      "gotchas": [
        "`any` spreads: a property read from an `any` value is `any` too, and so is the result of calling it.",
        "Under `strict`, a `catch` variable is already `unknown`.",
        "`unknown` in a union swallows the other members: `string | unknown` is just `unknown`."
      ],
      "faq": [
        {
          "q": "Should I use any or unknown in JSDoc?",
          "a": "`unknown`, unless you are deliberately switching checking off for a value. `unknown` keeps the checks and makes the narrowing explicit."
        }
      ],
      "related": [
        "types/union",
        "tags/type",
        "tags/throws",
        "guides/javascript-runtime-types-vs-annotations",
        "errors/ts7006",
        "errors/ts18046"
      ],
      "sources": [
        {
          "title": "TypeScript 3.0: new unknown top type",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "Everyday Types: any",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "null-and-undefined",
      "slug": "null-and-undefined",
      "title": "null, undefined and nullable types",
      "category": "Basics",
      "jsdoc": "{string | null}",
      "typescript": "string | null",
      "syntax": [
        {
          "use": "Nullable",
          "jsdoc": "/** @type {string | null} */",
          "typescript": ": string | null"
        },
        {
          "use": "Closure shorthand",
          "jsdoc": "/** @type {?string} */",
          "typescript": ": string | null"
        },
        {
          "use": "May be missing",
          "jsdoc": "/** @type {string | undefined} */",
          "typescript": ": string | undefined"
        },
        {
          "use": "Optional parameter",
          "jsdoc": "/** @param {string} [note] */",
          "typescript": "(note?: string)"
        }
      ],
      "since": null,
      "summary": "How to write a nullable type in JSDoc: {string | null}, the {?string} shorthand, and undefined. Why TypeScript makes you check before use, with strict on.",
      "intro": [
        "With `strict` (or `strictNullChecks`), `null` and `undefined` are not part of any other type. A value that may be absent says so in its type, `{string | null}`, and TypeScript makes you check it before you call methods on it.",
        "The checks matter most where JavaScript returns nothing on a miss: `document.querySelector` returns `null`, `Array.prototype.find` and `Map.prototype.get` return `undefined`. The examples show the errors for each (TS18047, TS18048) and the checks that clear them."
      ],
      "examples": [
        "types/nullable-find",
        "types/nullable-query",
        "types/nullable-param"
      ],
      "sections": [
        {
          "id": "null-or-undefined",
          "heading": "null or undefined?",
          "body": [
            "Use `undefined` for \"not provided\" (optional parameters and properties, missing map entries) and `null` for \"deliberately empty\" (a cleared field, an API's empty value). TypeScript treats them as different types: a `string | null` parameter does not accept `undefined`.",
            "`{?string}` is the Closure Compiler shorthand for `{string | null}`. TypeScript reads it that way, but prints the long form in its messages, so the long form is easier to match up."
          ]
        },
        {
          "id": "checking",
          "heading": "Checking before use",
          "body": [
            "`if (value)`, `if (value !== null)`, optional chaining `value?.name` and the `??` operator all narrow or handle the empty case. Inside the `if`, the type no longer includes `null` or `undefined`.",
            "JavaScript files cannot use TypeScript's `!` operator to assert a value is present; the type cast and assertion function alternatives are covered under [non-null assertions](/types/non-null-assertions/)."
          ]
        }
      ],
      "gotchas": [
        "Without `strict` or `strictNullChecks`, `null` and `undefined` are assignable to everything and `{?string}` adds nothing. Turn on `strict` before relying on these types.",
        "`if (count)` also skips `0` and `if (name)` skips the empty string. Compare with `!== undefined` when those are valid values."
      ],
      "faq": [
        {
          "q": "How do I make a type nullable in JSDoc?",
          "a": "Add `null` as a union member: `{string | null}`. The shorthand `{?string}` means the same."
        }
      ],
      "related": [
        "types/union",
        "types/any-and-unknown",
        "tags/param",
        "types/non-null-assertions",
        "types/nonnullable",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "Everyday Types: null and undefined values",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: nullable types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Narrowing: truthiness narrowing",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "void-and-never",
      "slug": "void-and-never",
      "title": "void and never",
      "category": "Basics",
      "jsdoc": "{void}",
      "typescript": "void",
      "syntax": [
        {
          "use": "Returns nothing useful",
          "jsdoc": "/** @returns {void} */",
          "typescript": "(): void"
        },
        {
          "use": "A callback whose result is ignored",
          "jsdoc": "/** @param {(id: string) => void} onSaved */",
          "typescript": "(onSaved: (id: string) => void)"
        },
        {
          "use": "Never returns",
          "jsdoc": "/** @returns {never} */",
          "typescript": "(): never"
        }
      ],
      "since": null,
      "summary": "void means a function's result is not used; never means a function never returns or a value cannot exist. How to write both in JSDoc and where each one helps.",
      "intro": [
        "`void` is the return type of a function whose result does not matter: `@returns {void}`. In a callback type, `(id: string) => void` means the caller will ignore whatever the callback returns, so a callback that happens to return something is still accepted.",
        "`never` is the type of something that cannot happen: a function that always throws, or a value after every possible case has been handled. TypeScript uses it to prove that code is exhaustive."
      ],
      "examples": [
        "types/void-callback",
        "types/never-exhaustive",
        "types/never-fail"
      ],
      "sections": [
        {
          "id": "exhaustive-checks",
          "heading": "Exhaustive checks with never",
          "body": [
            "After a `switch` has handled every member of a union, the value left in `default` has type `never`. Passing it to a function that takes `never` type-checks only while that is true. Add a member to the union without a matching `case`, and the call fails (TS2345), pointing you at the switch that needs updating, as the second example shows."
          ]
        },
        {
          "id": "functions-that-throw",
          "heading": "Functions that never return",
          "body": [
            "`@returns {never}` on a function that always throws tells TypeScript that code after a call to it is unreachable. In the third example, `stock` is `number` after `if (stock === undefined) fail(…)`, because the `fail` call ends that path.",
            "For that narrowing to work, the function needs the explicit `@returns {never}` and must be a declaration TypeScript can see, as here."
          ]
        }
      ],
      "gotchas": [
        "A function declared `@returns {void}` that returns a value is an error; a callback typed `=> void` that returns a value is not. The difference is deliberate, so `array.forEach((x) => list.push(x))` works.",
        "`undefined` and `void` are close but not the same: before TypeScript 5.1, a function typed to return `undefined` needed an explicit `return`."
      ],
      "faq": [
        {
          "q": "What does never mean in TypeScript?",
          "a": "A type with no values. A function returning `never` does not return at all, and a variable of type `never` can only exist in code TypeScript has proven unreachable."
        }
      ],
      "related": [
        "tags/returns",
        "types/union",
        "types/discriminated-unions",
        "tags/callback",
        "types/assertion-functions"
      ],
      "sources": [
        {
          "title": "More on Functions: void and never",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Narrowing: exhaustiveness checking",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "object-types",
      "slug": "object-types",
      "title": "object, Object and {}",
      "category": "Basics",
      "jsdoc": "{object}",
      "typescript": "object",
      "syntax": [
        {
          "use": "Any non-primitive",
          "jsdoc": "/** @type {object} */",
          "typescript": ": object"
        },
        {
          "use": "Almost anything",
          "jsdoc": "/** @type {Object} */ or /** @type {{}} */",
          "typescript": ": Object or : {}"
        },
        {
          "use": "A specific shape",
          "jsdoc": "/** @type {{ sku: string }} */",
          "typescript": ": { sku: string }"
        }
      ],
      "since": null,
      "summary": "In JSDoc, {object} accepts any non-primitive, while {Object} and {} accept almost any value. None describes properties; for that, write the object's shape.",
      "intro": [
        "Three similar spellings mean different things. `object` (lowercase) accepts any value that is not a primitive: objects, arrays, functions. `Object` (capitalized) and the empty type `{}` accept every value except `null` and `undefined`, numbers and strings included.",
        "None of them says what properties the value has, so reading `item.sku` from an `object` is an error (TS2339). When you know the shape, write it: `{{ sku: string, price: number }}`, or a `@typedef`."
      ],
      "examples": [
        "types/object-lowercase",
        "types/object-no-properties",
        "types/object-empty-braces"
      ],
      "sections": [
        {
          "id": "which-one",
          "heading": "Which one to write",
          "body": [
            "Write `object` for \"some object, I only pass it along\" (a cache key, an options bag you forward unchanged). Write the shape when you read properties from it. Avoid `Object` and `{}`: they look like \"an object\" but accept `42` and `\"text\"`, as the third example shows.",
            "In `@typedef {object} Name` followed by `@property` lines, `object` (or `Object`) is part of the tag syntax: it starts an object type whose properties the following lines describe."
          ]
        },
        {
          "id": "without-strict",
          "heading": "Without noImplicitAny",
          "body": [
            "The handbook notes that with `noImplicitAny` off, TypeScript reads `Object` and `object` in JSDoc as `any`. With `strict`, which turns `noImplicitAny` on, they keep the meanings above, which is what every example on this site uses."
          ]
        }
      ],
      "gotchas": [
        "Arrays and functions are objects: `configure([1, 2])` passes an `object` parameter.",
        "For a dictionary with string keys, write `Record<string, T>` rather than `object`."
      ],
      "faq": [
        {
          "q": "What is the difference between object and Object in JSDoc?",
          "a": "With `strict`, `object` accepts only non-primitive values, while `Object` accepts any value except `null` and `undefined`. Neither lists properties."
        }
      ],
      "related": [
        "types/object-shapes",
        "types/record",
        "types/primitives",
        "tags/typedef"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "More on Functions: object",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Object Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "arrays",
      "slug": "arrays",
      "title": "Arrays",
      "category": "Collections",
      "jsdoc": "{string[]}",
      "typescript": "string[]",
      "syntax": [
        {
          "use": "Array of strings",
          "jsdoc": "/** @type {string[]} */",
          "typescript": ": string[]"
        },
        {
          "use": "Generic spelling",
          "jsdoc": "/** @type {Array<string>} */",
          "typescript": ": Array<string>"
        },
        {
          "use": "Array of objects",
          "jsdoc": "/** @type {{ sku: string, quantity: number }[]} */",
          "typescript": ": { sku: string; quantity: number }[]"
        },
        {
          "use": "Closure spelling",
          "jsdoc": "/** @type {Array.<string>} */",
          "typescript": ": Array<string>"
        }
      ],
      "since": null,
      "summary": "Typing arrays in JSDoc: {string[]} or {Array<string>}, arrays of objects, union elements, and why an empty array literal needs a type in a .js file.",
      "intro": [
        "An array type is the element type followed by `[]`, as in `{string[]}`, or the generic form `{Array<string>}`; the two are the same type. TypeScript checks every element you add and types every element you read.",
        "For an array of objects, put the object type before the brackets, `{{ sku: string, quantity: number }[]}`, or name the object with `@typedef` and write `{LineItem[]}`."
      ],
      "examples": [
        "types/arrays-basic",
        "types/arrays-wrong-element",
        "types/arrays-empty-literal"
      ],
      "sections": [
        {
          "id": "empty-arrays",
          "heading": "Empty arrays need a type",
          "body": [
            "In a `.js` file, `const ids = []` starts as `any[]`, so anything can be pushed into it, and its element type becomes whatever was pushed, as the third example shows. Give empty arrays a type at the declaration: `/** @type {number[]} */ const ids = [];`.",
            "An array literal with elements is typed from them: `[\"S\", \"M\"]` is `string[]`."
          ]
        },
        {
          "id": "unions",
          "heading": "Arrays of unions",
          "body": [
            "Parentheses matter with unions. `{(string | number)[]}` is an array whose elements are strings or numbers; `{string | number[]}` is either one string or an array of numbers."
          ]
        }
      ],
      "gotchas": [
        "Reading `items[5]` is typed as the element type even when the array is shorter. The `noUncheckedIndexedAccess` option adds `undefined` to such reads.",
        "For an array that should not change, use `readonly string[]`; for a fixed number of elements, use a tuple."
      ],
      "faq": [
        {
          "q": "How do I write an array of objects in JSDoc?",
          "a": "`@type {{ name: string, price: number }[]}`, or define the object with `@typedef` and use `@type {Product[]}`. `Array<Product>` works too."
        },
        {
          "q": "Is Array<string> the same as string[]?",
          "a": "Yes. They are two spellings of one type, and the older `Array.<string>` is a third."
        }
      ],
      "related": [
        "types/tuples",
        "types/readonly-arrays",
        "types/object-shapes",
        "tags/typedef"
      ],
      "sources": [
        {
          "title": "Everyday Types: arrays",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Type Checking JavaScript Files: empty array initializers",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "tuples",
      "slug": "tuples",
      "title": "Tuples",
      "category": "Collections",
      "jsdoc": "{[number, number]}",
      "typescript": "[number, number]",
      "syntax": [
        {
          "use": "Fixed length",
          "jsdoc": "/** @type {[number, number]} */",
          "typescript": ": [number, number]"
        },
        {
          "use": "Named elements",
          "jsdoc": "/** @returns {[min: number, max: number]} */",
          "typescript": "(): [min: number, max: number]"
        },
        {
          "use": "Optional element",
          "jsdoc": "/** @type {[sku: string, quantity?: number]} */",
          "typescript": ": [sku: string, quantity?: number]"
        },
        {
          "use": "Rest elements",
          "jsdoc": "/** @type {[label: string, ...values: number[]]} */",
          "typescript": ": [label: string, ...values: number[]]"
        }
      ],
      "since": null,
      "summary": "A tuple is an array with a fixed length and a type per position. Writing tuples in JSDoc, with named, optional and rest elements, and when you need one.",
      "intro": [
        "A tuple type such as `{[number, number]}` describes an array with exactly two elements, both numbers. Each position can have its own type, `{[string, number]}`, and TypeScript checks the length as well as the elements.",
        "Tuples suit small fixed groups returned from a function, such as a minimum and maximum, or a key and a value. Elements can be named (`[min: number, max: number]`), optional (`quantity?: number`) and followed by a rest element (`...values: number[]`)."
      ],
      "examples": [
        "types/tuples-basic",
        "types/tuples-length",
        "types/tuples-inferred-array"
      ],
      "sections": [
        {
          "id": "inference",
          "heading": "An array literal is not a tuple",
          "body": [
            "Without a type, `return [min, max]` is inferred as `number[]`, an array of any length. Assigning that to a `[number, number]` fails (TS2322, \"Target requires 2 element(s) but source may have fewer\"), as the third example shows. Declare the tuple on the function with `@returns {[number, number]}`, or use a `const` assertion, which makes a read-only tuple."
          ]
        },
        {
          "id": "names",
          "heading": "Element names",
          "body": [
            "Names in a tuple type are documentation: they appear in hovers and completions, and they do not change how you destructure the value. TypeScript added named tuple elements in version 4.0, and optional and rest elements in 3.0."
          ]
        }
      ],
      "gotchas": [
        "Tuples are still mutable arrays: `range.push(3)` passes. Make them `readonly [number, number]` when that matters.",
        "Past three or four elements, an object with named properties is easier to read than a tuple."
      ],
      "faq": [
        {
          "q": "How do I return two values from a function with JSDoc types?",
          "a": "Return a tuple and declare it: `@returns {[min: number, max: number]}`. Callers destructure it, `const [low, high] = priceRange(prices)`."
        }
      ],
      "related": [
        "types/arrays",
        "types/readonly-arrays",
        "tags/returns",
        "types/object-shapes"
      ],
      "sources": [
        {
          "title": "Object Types: tuple types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 4.0: labeled tuple elements",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "TypeScript 3.0: optional and rest elements in tuple types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "object-shapes",
      "slug": "object-shapes",
      "title": "Object shapes",
      "category": "Collections",
      "jsdoc": "{{ street: string, unit?: string }}",
      "typescript": "{ street: string; unit?: string }",
      "syntax": [
        {
          "use": "Inline",
          "jsdoc": "/** @param {{ street: string, city: string }} address */",
          "typescript": "(address: { street: string; city: string })"
        },
        {
          "use": "Optional property",
          "jsdoc": "{{ unit?: string }}",
          "typescript": "{ unit?: string }"
        },
        {
          "use": "Named",
          "jsdoc": "/** @typedef {{ street: string, city: string }} Address */",
          "typescript": "type Address = { street: string; city: string };"
        }
      ],
      "since": null,
      "summary": "Writing an object type inline in JSDoc: double braces, optional properties with ?, commas or semicolons, and the postfix = that does not mean optional.",
      "intro": [
        "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."
      ],
      "examples": [
        "types/shapes-basic",
        "types/shapes-excess",
        "types/shapes-postfix-equals"
      ],
      "sections": [
        {
          "id": "excess-properties",
          "heading": "Misspelled properties",
          "body": [
            "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."
          ]
        },
        {
          "id": "postfix-equals",
          "heading": "The postfix = is not optional",
          "body": [
            "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](/errors/ts1247/) and TS1109) and then treats the property as required (TS2741 on the object), as the third example shows. Write `unit?: string`."
          ]
        },
        {
          "id": "inline-or-named",
          "heading": "Inline or named?",
          "body": [
            "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."
      ],
      "faq": [
        {
          "q": "How do I write an object type in JSDoc?",
          "a": "Inside the tag's braces, write the type's own braces with the properties: `@param {{ id: string, tags?: string[] }} item`."
        }
      ],
      "related": [
        "tags/typedef",
        "tags/property",
        "types/object-types",
        "types/record"
      ],
      "sources": [
        {
          "title": "Object Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: unsupported patterns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "record",
      "slug": "record",
      "title": "Record<K, V> and Object.<K, V>",
      "category": "Collections",
      "jsdoc": "{Record<string, number>}",
      "typescript": "Record<string, number>",
      "syntax": [
        {
          "use": "Any string key",
          "jsdoc": "/** @type {Record<string, number>} */",
          "typescript": ": Record<string, number>"
        },
        {
          "use": "A fixed set of keys",
          "jsdoc": "/** @type {Record<\"S\" | \"M\" | \"L\", number>} */",
          "typescript": ": Record<\"S\" | \"M\" | \"L\", number>"
        },
        {
          "use": "Index signature",
          "jsdoc": "/** @type {{ [sku: string]: number }} */",
          "typescript": ": { [sku: string]: number }"
        },
        {
          "use": "Closure spelling",
          "jsdoc": "/** @type {Object.<string, number>} */",
          "typescript": ": { [x: string]: number }"
        }
      ],
      "since": null,
      "summary": "Record<K, V> types an object used as a dictionary. In JSDoc it is written as in TypeScript; Object.<K, V> and index signatures mean the same thing.",
      "intro": [
        "`Record<K, V>` is the type of an object whose keys are of type `K` and whose values are of type `V`. `{Record<string, number>}` fits a stock table keyed by SKU; `{Record<\"S\" | \"M\" | \"L\", number>}` requires exactly those three keys.",
        "Two older spellings mean the same as `Record<string, number>`: the index signature `{{ [sku: string]: number }}` and the Closure form `{Object.<string, number>}`. TypeScript accepts all three; `Record` is the shortest and works with a union of keys."
      ],
      "examples": [
        "types/record-stock",
        "types/record-keys",
        "types/record-closure-spellings",
        "types/record-unchecked-index"
      ],
      "sections": [
        {
          "id": "union-keys",
          "heading": "A union of keys",
          "body": [
            "With literal keys, `Record` is complete or it is an error: leaving out `L` from a `Record<Size, number>` is TS2741, as the second example shows. That makes it a good fit for lookup tables that must cover every case of a union."
          ]
        },
        {
          "id": "lookups",
          "heading": "Lookups that may miss",
          "body": [
            "By default, `stock[sku]` on a `Record<string, number>` is typed `number`, even for a key that is not there. With `noUncheckedIndexedAccess`, TypeScript adds `undefined` to the result and asks for a check (TS2532 in the fourth example), which matches what happens at run time.",
            "For a dictionary that changes a lot, a `Map<string, number>` is often clearer: `get()` is always typed as possibly `undefined`, and keys are not mixed with object properties."
          ]
        }
      ],
      "gotchas": [
        "`Record<string, V>` claims every string key exists. Prefer `Partial<Record<string, V>>` or `Map` when that is not true and `noUncheckedIndexedAccess` is off."
      ],
      "faq": [
        {
          "q": "How do I type an object with dynamic keys in JSDoc?",
          "a": "`@type {Record<string, number>}` for string keys and number values. `{Object.<string, number>}` and `{{ [key: string]: number }}` are equivalent spellings."
        }
      ],
      "related": [
        "types/map-and-set",
        "types/object-shapes",
        "types/object-types",
        "tags/typedef",
        "config/no-unchecked-indexed-access",
        "types/closure-syntax"
      ],
      "sources": [
        {
          "title": "Utility Types: Record<Keys, Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: Object.<K, V>",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Object Types: index signatures",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "map-and-set",
      "slug": "map-and-set",
      "title": "Map, Set and WeakMap",
      "category": "Collections",
      "jsdoc": "{Map<string, number>}",
      "typescript": "Map<string, number>",
      "syntax": [
        {
          "use": "A Map",
          "jsdoc": "/** @type {Map<string, number>} */\nconst stock = new Map();",
          "typescript": "const stock = new Map<string, number>();"
        },
        {
          "use": "A Set",
          "jsdoc": "/** @type {Set<string>} */\nconst tags = new Set();",
          "typescript": "const tags = new Set<string>();"
        },
        {
          "use": "A WeakMap",
          "jsdoc": "/** @type {WeakMap<HTMLElement, number>} */",
          "typescript": ": WeakMap<HTMLElement, number>"
        }
      ],
      "since": null,
      "summary": "Typing Map, Set, WeakMap and WeakSet in JSDoc: put the type arguments in @type, because new Map() alone is Map<any, any>. Examples of get, set and has.",
      "intro": [
        "`Map<K, V>`, `Set<T>`, `WeakMap<K, V>` and `WeakSet<T>` take their key and value types as type arguments. In a `.js` file you cannot write `new Map<string, number>()`, so give the variable the type with `@type {Map<string, number>}` and create it with `new Map()`.",
        "Without a type and without initial entries, `new Map()` is `Map<any, any>` and checks nothing, as the last example shows. With initial entries, `new Map([[\"TEE-01\", 12]])` infers `Map<string, number>` from them."
      ],
      "examples": [
        "types/map-set-basic",
        "types/map-wrong-value",
        "types/map-get-undefined",
        "types/map-untyped"
      ],
      "sections": [
        {
          "id": "get-may-miss",
          "heading": "get() may miss",
          "body": [
            "`Map.prototype.get` returns `V | undefined`, so using the result directly is an error (TS2532 in the third example). Handle the miss with `??`, an `if`, or a `has()` check followed by a `get()` (TypeScript does not connect the two calls, so you may still need the `??`)."
          ]
        },
        {
          "id": "weak-collections",
          "heading": "WeakMap and WeakSet",
          "body": [
            "Weak collections need object keys, so their key type must be an object type such as `HTMLElement` or `object`; a string key is an error. They suit data attached to DOM nodes or other objects you do not own."
          ]
        }
      ],
      "gotchas": [
        "Class fields work the same way: `/** @type {Map<string, Product>} */ #byId = new Map();`.",
        "Iterating a `Map` gives `[K, V]` tuples, so `for (const [sku, count] of stock)` types both."
      ],
      "faq": [
        {
          "q": "How do I type a Map in JSDoc?",
          "a": "Put the type on the variable: `/** @type {Map<string, number>} */ const stock = new Map();`. The type arguments then apply to every `get`, `set` and loop."
        }
      ],
      "related": [
        "types/record",
        "types/arrays",
        "tags/type",
        "tags/extends"
      ],
      "sources": [
        {
          "title": "Generics: generic types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/generics.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Map",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map",
          "publisher": "MDN"
        },
        {
          "title": "WeakMap",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap",
          "publisher": "MDN"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "promise",
      "slug": "promise",
      "title": "Promise and async functions",
      "category": "Collections",
      "jsdoc": "{Promise<Product[]>}",
      "typescript": "Promise<Product[]>",
      "syntax": [
        {
          "use": "An async function",
          "jsdoc": "/** @returns {Promise<Product[]>} */\nasync function load() {}",
          "typescript": "async function load(): Promise<Product[]> {}"
        },
        {
          "use": "A promise parameter",
          "jsdoc": "/** @param {Promise<Response>} pending */",
          "typescript": "(pending: Promise<Response>)"
        },
        {
          "use": "A promise of nothing",
          "jsdoc": "/** @returns {Promise<void>} */",
          "typescript": "(): Promise<void>"
        }
      ],
      "since": null,
      "summary": "Typing promises and async functions in JSDoc: @returns {Promise<T>}, typing fetch().json() results, new Promise, and the missing-await error TypeScript catches.",
      "intro": [
        "`Promise<T>` is the type of a promise that resolves to a `T`. An `async` function always returns one, so its JSDoc says `@returns {Promise<T>}` and its `return` statements return plain `T` values. `await` unwraps the type again: `await loadProducts()` is `Product[]`.",
        "Because the promise and its value have different types, a forgotten `await` is caught: reading `.length` from a `Promise<string[]>` is TS2339, as the second example shows."
      ],
      "examples": [
        "types/promise-fetch",
        "types/promise-not-awaited",
        "types/promise-delay"
      ],
      "sections": [
        {
          "id": "json-results",
          "heading": "Typing JSON from fetch",
          "body": [
            "`response.json()` returns `Promise<any>`, so its result is unchecked. The first example casts it to the expected type with `/** @type {Product[]} */ (await response.json())`. The cast is a claim, not a check; for data you do not control, cast to `unknown` and validate instead."
          ]
        },
        {
          "id": "new-promise",
          "heading": "new Promise",
          "body": [
            "A function that builds a promise with `new Promise` declares the resolved type in `@returns`, as `delay()` does with `Promise<void>`; TypeScript then checks what `resolve` is called with. Generic helpers such as `withTimeout` take `@template T` so the result keeps the input's type."
          ]
        }
      ],
      "gotchas": [
        "An `async` function's return type must be written as `Promise<T>`; `@returns {T}` alone is [TS1064](/errors/ts1064/).",
        "`Promise.all([a, b])` is typed as a tuple of the resolved types, so destructuring its result keeps each type."
      ],
      "faq": [
        {
          "q": "How do I document the return type of an async function in JSDoc?",
          "a": "`@returns {Promise<T>}`, where `T` is the resolved value. For an async function that resolves to nothing, `@returns {Promise<void>}`."
        }
      ],
      "related": [
        "tags/returns",
        "tags/async",
        "tags/template",
        "types/awaited",
        "types/type-casts",
        "recipes/type-an-express-handler"
      ],
      "sources": [
        {
          "title": "Everyday Types: functions which return promises",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Using promises",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises",
          "publisher": "MDN"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "readonly-arrays",
      "slug": "readonly-arrays",
      "title": "Readonly arrays",
      "category": "Collections",
      "jsdoc": "{readonly string[]}",
      "typescript": "readonly string[]",
      "syntax": [
        {
          "use": "A read-only array",
          "jsdoc": "/** @param {readonly string[]} sizes */",
          "typescript": "(sizes: readonly string[])"
        },
        {
          "use": "Generic spelling",
          "jsdoc": "/** @param {ReadonlyArray<string>} sizes */",
          "typescript": "(sizes: ReadonlyArray<string>)"
        },
        {
          "use": "A read-only tuple",
          "jsdoc": "/** @type {readonly [number, number]} */",
          "typescript": ": readonly [number, number]"
        }
      ],
      "since": null,
      "summary": "readonly string[] and ReadonlyArray<string> are arrays without push, sort or other changing methods. Use them to promise a function leaves its input alone.",
      "intro": [
        "A read-only array type, `{readonly string[]}` or `{ReadonlyArray<string>}`, has every array method that does not change the array (`map`, `filter`, `slice`, indexing) and none that does (`push`, `splice`, `sort`, index assignment). Calling one is an error (TS2339), as the first example shows.",
        "It is most useful on parameters. `@param {readonly string[]} sizes` tells callers that the function will not modify their array, and TypeScript holds the function to it. Ordinary arrays can be passed where a readonly array is expected."
      ],
      "examples": [
        "types/readonly-arrays-push",
        "types/readonly-arrays-copy"
      ],
      "sections": [
        {
          "id": "working-with-them",
          "heading": "Working with them",
          "body": [
            "To sort or extend, copy first: `[...sizes].sort()` returns a new, mutable `string[]`. Methods that already return new arrays, such as `map` and `filter`, work directly.",
            "TypeScript added the `readonly` array syntax in version 3.4. A `const` assertion on an array literal, `/** @type {const} */ ([\"S\", \"M\"])`, produces a read-only tuple."
          ]
        }
      ],
      "gotchas": [
        "Read-only exists only in the types: TypeScript checks it, the running code does not. `Object.freeze(array)` makes it read-only at run time as well, and TypeScript types the result as `readonly T[]`.",
        "A `readonly string[]` cannot be passed where a mutable `string[]` is expected, because the receiver might change it. Mark parameters readonly from the bottom up."
      ],
      "faq": [
        {
          "q": "What is the difference between readonly string[] and ReadonlyArray<string>?",
          "a": "None; they are two spellings of the same type."
        }
      ],
      "related": [
        "types/arrays",
        "types/tuples",
        "tags/readonly",
        "types/readonly",
        "types/const-assertions"
      ],
      "sources": [
        {
          "title": "TypeScript 3.4: improvements for ReadonlyArray and readonly tuples",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "Object Types: the ReadonlyArray type",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "function-types",
      "slug": "function-types",
      "title": "Function types",
      "category": "Functions",
      "jsdoc": "{(price: number) => string}",
      "typescript": "(price: number) => string",
      "syntax": [
        {
          "use": "Arrow syntax",
          "jsdoc": "/** @type {(amount: number, currency?: string) => string} */",
          "typescript": ": (amount: number, currency?: string) => string"
        },
        {
          "use": "Closure syntax",
          "jsdoc": "/** @type {function(number, string=): string} */",
          "typescript": ": (amount: number, currency?: string) => string"
        },
        {
          "use": "A callback parameter",
          "jsdoc": "/** @param {(a: Product, b: Product) => number} compare */",
          "typescript": "(compare: (a: Product, b: Product) => number)"
        },
        {
          "use": "Any function",
          "jsdoc": "/** @type {Function} */",
          "typescript": ": Function"
        }
      ],
      "summary": "Writing function types in JSDoc: TypeScript's arrow syntax (price: number) => string, the older function(number): string, and Function. Examples and errors.",
      "intro": [
        "A function type describes a function's parameters and return type. TypeScript's arrow syntax works inside JSDoc braces unchanged: `@param {(a: Product, b: Product) => number} compare`. The parameter names are for readers; only the types and their order are checked.",
        "The Closure Compiler form, `{function(number, string=): string}`, also works: parameters are listed by type only, `=` marks an optional one, and the return type follows a colon. The arrow form is the one TypeScript uses in its messages."
      ],
      "examples": [
        "types/fn-types-arrow",
        "types/fn-types-closure",
        "types/fn-types-mismatch"
      ],
      "sections": [
        {
          "id": "typing-a-function-value",
          "heading": "Typing a function value",
          "body": [
            "`@type` with a function type on a `const` types the parameters of the function assigned to it, so the arrow function needs no `@param` tags. For a function declaration, `@param` and `@returns` are the usual route.",
            "Callbacks passed inline take their parameter types from the function type they are passed to, as `(a, b) => a.price - b.price` does in the first example."
          ]
        },
        {
          "id": "the-function-type",
          "heading": "The Function type",
          "body": [
            "`{Function}` (and `{function}` in lowercase) accepts any function and returns `any` when called, so it checks almost nothing. Prefer a specific function type, or `(...args: never[]) => unknown` when you only need \"some function\"."
          ]
        }
      ],
      "gotchas": [
        "A callback that returns the wrong type is reported inside the callback: `(a, b) => a > b` returns a boolean where `number` is expected, and the error points at `a > b` (TS2322).",
        "A function with fewer parameters than the type is fine: `(a) => …` can be passed where `(a, b) => …` is expected, as in JavaScript.",
        "TypeScript 7.0 does not parse the Closure spelling `function(string): number` (the section [Under TypeScript 6.0 and 7.0](#typescript-6-0-and-7-0) has what 7.0.2 reports); the arrow spelling works in every version."
      ],
      "faq": [
        {
          "q": "How do I write a function type in JSDoc?",
          "a": "Use arrow syntax inside the braces: `{(input: string) => boolean}`. For a reusable name, put it in a `@typedef` or write a `@callback`."
        }
      ],
      "related": [
        "tags/callback",
        "tags/type",
        "tags/param",
        "types/optional-parameters",
        "typescript/7-0"
      ],
      "sources": [
        {
          "title": "More on Functions: function type expressions",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: function types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "optional-parameters",
      "slug": "optional-parameters",
      "title": "Optional and default parameters",
      "category": "Functions",
      "jsdoc": "{string} [label]",
      "typescript": "label?: string",
      "syntax": [
        {
          "use": "Optional",
          "jsdoc": "/** @param {string} [label] */",
          "typescript": "(label?: string)"
        },
        {
          "use": "With a default",
          "jsdoc": "/** @param {number} [copies=1] */\nfunction f(copies = 1) {}",
          "typescript": "function f(copies: number = 1) {}"
        },
        {
          "use": "Closure spelling",
          "jsdoc": "/** @param {boolean=} large */",
          "typescript": "(large?: boolean)"
        },
        {
          "use": "In a function type",
          "jsdoc": "{(sku: string, label?: string) => void}",
          "typescript": "(sku: string, label?: string) => void"
        }
      ],
      "summary": "How to mark a JSDoc parameter optional: [name], name= in the type, or a default value. Why typed parameters become required, and the undefined check inside.",
      "intro": [
        "Square brackets around the parameter name, `@param {string} [label]`, make it optional: callers may leave it out, and inside the function its type is `string | undefined`. A default goes inside the brackets for readers, `[copies=1]`, and in the code for the run time, `function f(copies = 1)`.",
        "Typed parameters are required unless marked optional. Calling `addLine(\"TEE-01\")` when both parameters have `@param` types is TS2554 (\"Expected 2 arguments, but got 1\"), as the third example shows. Untyped parameters in a `.js` file are the exception: TypeScript treats them as optional."
      ],
      "examples": [
        "types/optional-params-basic",
        "types/optional-params-undefined",
        "types/optional-params-required"
      ],
      "sections": [
        {
          "id": "undefined-inside",
          "heading": "undefined inside the function",
          "body": [
            "An optional parameter without a default may be `undefined`, so calling a method on it is TS18048 (\"'label' is possibly 'undefined'\"). Check it, use `??` for a fallback, or give it a default in the code; a default removes `undefined` from the type."
          ]
        },
        {
          "id": "three-spellings",
          "heading": "Three spellings",
          "body": [
            "`[label]` in the `@param` tag, `{string=}` in the type (Closure style) and `label?:` inside a function type all mean the same thing. Use brackets in `@param` tags and `?:` inside types; the `=` suffix only works in `@param` and function types, not on object properties."
          ]
        }
      ],
      "gotchas": [
        "Passing `undefined` explicitly is allowed for an optional parameter, as the first example does to skip `label`; for a parameter with a default, it makes the default apply."
      ],
      "faq": [
        {
          "q": "How do I document a default value in JSDoc?",
          "a": "Write it in the brackets, `@param {number} [copies=1]`, and also in the function's parameter list. TypeScript uses the one in the code; the one in the comment is for readers and editors."
        }
      ],
      "related": [
        "tags/param",
        "types/rest-parameters",
        "types/null-and-undefined",
        "types/function-types"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @param",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "More on Functions: optional parameters",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Type Checking JavaScript Files: parameters are optional by default",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "rest-parameters",
      "slug": "rest-parameters",
      "title": "Rest parameters",
      "category": "Functions",
      "jsdoc": "{...string}",
      "typescript": "...tags: string[]",
      "syntax": [
        {
          "use": "A rest parameter",
          "jsdoc": "/** @param {...string} tags */\nfunction f(...tags) {}",
          "typescript": "function f(...tags: string[]) {}"
        },
        {
          "use": "In a function type",
          "jsdoc": "{(...tags: string[]) => void}",
          "typescript": "(...tags: string[]) => void"
        }
      ],
      "summary": "A rest parameter in JSDoc is written @param {...string} tags: the element type after three dots. Inside the function the parameter is a string[]. Examples.",
      "intro": [
        "For a rest parameter, `function tagProduct(sku, ...tags)`, the `@param` type is the type of one argument with three dots in front: `@param {...string} tags`. Inside the function, `tags` is `string[]`, and every extra argument at a call is checked against `string` (TS2345 for a number, as the second example shows).",
        "Inside a function type the TypeScript form applies: `{(...tags: string[]) => void}`, with the array type after the colon."
      ],
      "examples": [
        "types/rest-params",
        "types/rest-params-wrong",
        "types/rest-params-arguments"
      ],
      "sections": [
        {
          "id": "arguments",
          "heading": "Functions that read arguments",
          "body": [
            "Older code reads extra values from `arguments` instead of declaring a rest parameter. TypeScript notices the use of `arguments` in a `.js` file and lets callers pass any number of values, as the third example shows; the values themselves are not typed. Converting to a rest parameter with a `@param {...T}` type gives the same freedom with checking."
          ]
        }
      ],
      "gotchas": [
        "Write the element type in `@param`, not the array type: `{...string}`, not `{...string[]}`.",
        "TypeScript 7.0 no longer lets callers pass extra values to a function just because it reads `arguments` (the section [Under TypeScript 6.0 and 7.0](#typescript-6-0-and-7-0) has what 7.0.2 reports); declare a rest parameter instead."
      ],
      "faq": [
        {
          "q": "How do I document a variadic function in JSDoc?",
          "a": "Declare a rest parameter and type one element of it: `@param {...number} values` for `function sum(...values)`."
        }
      ],
      "related": [
        "tags/param",
        "types/optional-parameters",
        "types/tuples",
        "types/function-types",
        "typescript/7-0"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @param",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "More on Functions: rest parameters and arguments",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Type Checking JavaScript Files: var-args parameters",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "this-parameter",
      "slug": "this-parameter",
      "title": "this parameters",
      "category": "Functions",
      "jsdoc": "{(this: HTMLInputElement, event: Event) => void}",
      "typescript": "(this: HTMLInputElement, event: Event) => void",
      "syntax": [
        {
          "use": "In a function type",
          "jsdoc": "/** @type {(this: HTMLInputElement, event: Event) => void} */",
          "typescript": ": (this: HTMLInputElement, event: Event) => void"
        },
        {
          "use": "On a declaration",
          "jsdoc": "/** @this {HTMLInputElement} */\nfunction trim() {}",
          "typescript": "function trim(this: HTMLInputElement) {}"
        },
        {
          "use": "In a method type",
          "jsdoc": "{{ total(this: Cart): number }}",
          "typescript": "{ total(this: Cart): number }"
        }
      ],
      "summary": "A this parameter types this inside a function. In JSDoc, write it first in a function type, (this: HTMLInputElement) => void, or use @this on a declaration.",
      "intro": [
        "TypeScript lets a function type declare the type of `this` as a first, fake parameter: `(this: HTMLInputElement, event: Event) => void`. It is not a real argument; callers pass only `event`. In a `.js` file you write it inside a function type, or use the `@this` tag on a function declaration.",
        "The declaration is checked at both ends: inside the function `this` has the declared type, and a call that would give it a different `this` (or none) is an error, as the second example shows with [TS2684](/errors/ts2684/)."
      ],
      "examples": [
        "types/this-param-type",
        "types/this-param-detached",
        "types/this-param-arrow"
      ],
      "sections": [
        {
          "id": "detached-methods",
          "heading": "Detached methods",
          "body": [
            "A method declared with a `this` parameter cannot be pulled off its object and called on its own: `const { total } = cart; total()` calls it with no `this`, which TypeScript reports as [TS2684](/errors/ts2684/) (\"The 'this' context of type 'void' is not assignable…\"). Without the `this` parameter, the same mistake fails only at run time."
          ]
        },
        {
          "id": "arrow-functions",
          "heading": "Arrow functions",
          "body": [
            "Arrow functions do not have their own `this`, so a `this` parameter in the type does not apply to them. In the third example the arrow function's `this` is the module's `this`, which is `undefined` in an ES module, and TypeScript reports TS2532. Use a `function` expression when the code needs the declared `this`."
          ]
        }
      ],
      "gotchas": [
        "The `this` parameter must come first in the list.",
        "Utility types read it: `ThisParameterType<F>` extracts it and `OmitThisParameter<F>` removes it."
      ],
      "faq": [
        {
          "q": "How do I declare the type of this in a JSDoc function type?",
          "a": "As a first parameter named `this`: `@type {(this: HTMLElement, event: MouseEvent) => void}`. For a function declaration, `@this {HTMLElement}` does the same."
        }
      ],
      "related": [
        "tags/this",
        "types/function-types",
        "tags/type",
        "errors/ts2683",
        "config/no-implicit-this"
      ],
      "sources": [
        {
          "title": "More on Functions: declaring this in a function",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @this",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "constructor-types",
      "slug": "constructor-types",
      "title": "Constructor types",
      "category": "Functions",
      "jsdoc": "{new (sku: string) => T}",
      "typescript": "new (sku: string) => T",
      "syntax": [
        {
          "use": "Something you call with new",
          "jsdoc": "/** @param {new (sku: string) => Shirt} Kind */",
          "typescript": "(Kind: new (sku: string) => Shirt)"
        },
        {
          "use": "A specific class",
          "jsdoc": "/** @param {typeof Shirt} Kind */",
          "typescript": "(Kind: typeof Shirt)"
        },
        {
          "use": "Closure spelling",
          "jsdoc": "{function(new: Shirt, string)}",
          "typescript": "new (sku: string) => Shirt"
        }
      ],
      "summary": "A constructor type describes a class passed as a value: new (sku: string) => T, or typeof Shirt for one class. Both in JSDoc, with a generic factory.",
      "intro": [
        "When a function takes a class as an argument, the parameter's type is a constructor type: `{new (sku: string) => T}` means \"something you can call with `new` and a string, which produces a `T`\". Any class with a compatible constructor fits, and the result of `new Kind(…)` is typed `T`.",
        "`{typeof Shirt}` is the constructor type of one particular class, static members included. Use it when the code needs `Shirt`'s statics, such as `Kind.category` in the second example."
      ],
      "examples": [
        "types/ctor-types-factory",
        "types/ctor-types-typeof",
        "types/ctor-types-not-constructible"
      ],
      "sections": [
        {
          "id": "generic-factories",
          "heading": "Generic factories",
          "body": [
            "Combine a constructor type with `@template T` to keep the instance type: `createAll(Shirt, skus)` returns `Shirt[]`, so `shirts[0].size` is checked. That pattern is common for registries, dependency injection and test helpers."
          ]
        },
        {
          "id": "plain-functions",
          "heading": "Plain functions do not fit",
          "body": [
            "An arrow function or a factory function cannot be called with `new`, so passing one where a constructor type is expected is TS2345, as the third example shows. If both should be accepted, take a function type instead and call it without `new`."
          ]
        }
      ],
      "gotchas": [
        "In a `.ts` file an abstract class cannot be created with `new`, so it does not fit a `new (…) => T` parameter; JavaScript has no abstract classes, so this only matters for classes declared in `.d.ts` files.",
        "The Closure form `{function(new: Shirt, string)}` is read as a constructor type that takes a string and creates a `Shirt`."
      ],
      "faq": [
        {
          "q": "How do I type a class passed as a parameter in JSDoc?",
          "a": "With a constructor type, `{new (...args: any[]) => T}`, or with `{typeof MyClass}` for one specific class."
        }
      ],
      "related": [
        "tags/class",
        "tags/template",
        "types/function-types",
        "types/typeof",
        "types/other-utility-types"
      ],
      "sources": [
        {
          "title": "More on Functions: construct signatures",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Generics: using class types in generics",
          "url": "https://www.typescriptlang.org/docs/handbook/2/generics.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "type-predicates",
      "slug": "type-predicates",
      "title": "Type predicates",
      "category": "Functions",
      "jsdoc": "{item is Product}",
      "typescript": "item is Product",
      "syntax": [
        {
          "use": "A type guard",
          "jsdoc": "/**\n * @param {Product | Bundle} item\n * @returns {item is Product}\n */",
          "typescript": "function isProduct(item: Product | Bundle): item is Product"
        }
      ],
      "summary": "A type predicate, @returns {item is Product}, turns a boolean function into a type guard that narrows in if statements and filter(). JSDoc syntax and examples.",
      "intro": [
        "A function whose JSDoc says `@returns {item is Product}` returns a boolean, and TypeScript also learns from it: wherever the call returns `true`, `item` is a `Product`. Such a function is a user-defined type guard. It narrows inside `if (isProduct(item))` and turns `items.filter(isProduct)` into a `Product[]`.",
        "With a plain `@returns {boolean}`, the same function narrows nothing, as the second example shows: TypeScript does not look inside the function body to work out what `true` means."
      ],
      "examples": [
        "types/predicate-filter",
        "types/predicate-boolean",
        "types/predicate-inferred"
      ],
      "sections": [
        {
          "id": "inferred-predicates",
          "heading": "Inferred predicates",
          "body": [
            "TypeScript 5.5 added inferred type predicates: a function that returns a simple check on its parameter, such as `(sku) => sku !== undefined`, is treated as a predicate without any annotation. That is why the third example's `filter` returns `string[]`. Functions with more complex bodies, or that are declared `@returns {boolean}`, still need the explicit predicate."
          ]
        },
        {
          "id": "keeping-them-honest",
          "heading": "Keeping them honest",
          "body": [
            "TypeScript trusts the predicate: if `isProduct` returns `true` for a bundle, the narrowing is wrong and nothing reports it. Keep guards small and make them test the property that actually tells the types apart, like the `kind` field here."
          ]
        }
      ],
      "gotchas": [
        "The name in the predicate must be one of the function's parameters: `@returns {item is Product}` for a parameter named `item`.",
        "For checks that should throw rather than return false, use an assertion function instead."
      ],
      "faq": [
        {
          "q": "How do I write a type guard in JSDoc?",
          "a": "Return a boolean and declare it as a predicate: `@returns {value is string}` on a function whose parameter is named `value`."
        }
      ],
      "related": [
        "types/assertion-functions",
        "types/union",
        "types/any-and-unknown",
        "guides/javascript-runtime-types-vs-annotations"
      ],
      "sources": [
        {
          "title": "Narrowing: using type predicates",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 5.5: inferred type predicates",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "assertion-functions",
      "slug": "assertion-functions",
      "title": "Assertion functions",
      "category": "Functions",
      "jsdoc": "{asserts value is string}",
      "typescript": "asserts value is string",
      "syntax": [
        {
          "use": "Asserts a type",
          "jsdoc": "/** @returns {asserts value is string} */",
          "typescript": "(): asserts value is string"
        },
        {
          "use": "Asserts a condition",
          "jsdoc": "/** @returns {asserts condition} */",
          "typescript": "(): asserts condition"
        }
      ],
      "summary": "An assertion function throws unless a check holds, and TypeScript narrows the code after it. JSDoc: @returns {asserts value is string} or {asserts condition}.",
      "intro": [
        "An assertion function either returns normally or throws. Declaring it with `@returns {asserts value is string}` tells TypeScript that if the call returns, `value` is a string, so the code after the call can use it as one. TypeScript added assertion functions in version 3.7.",
        "`@returns {asserts condition}` is the general form: after `assert(product.price !== undefined, …)`, TypeScript treats `product.price` as defined, whatever the check was."
      ],
      "examples": [
        "types/asserts-type",
        "types/asserts-condition",
        "types/asserts-wrong-use"
      ],
      "sections": [
        {
          "id": "predicate-or-assertion",
          "heading": "Predicate or assertion?",
          "body": [
            "A type predicate (`value is string`) returns a boolean and narrows inside an `if`. An assertion function throws instead and narrows everything after the call, which reads better at the top of a function that validates its input, as in the first example."
          ]
        },
        {
          "id": "rules",
          "heading": "Rules TypeScript applies",
          "body": [
            "TypeScript needs to know the function is an assertion before it narrows, so the function must have an explicit type: a JSDoc `@returns {asserts …}` on a declaration or on the function itself, or an `@type` with an asserting function type on the variable that holds it. The examples on this page use declarations.",
            "The narrowing is real: after `assertString(quantity)`, `quantity` is a `string`, so `quantity.toFixed(0)` is an error (TS2551), as the third example shows."
          ]
        }
      ],
      "gotchas": [
        "An assertion function's own return type is `void`; it cannot also return a value.",
        "Node's `assert` module and many test libraries ship typings with `asserts`, so `assert(x)` from them narrows the same way."
      ],
      "faq": [
        {
          "q": "How do I write an assertion function in JavaScript with JSDoc?",
          "a": "Write a function that throws when the check fails, and give it `@returns {asserts value is T}` (or `@returns {asserts condition}` for a boolean condition parameter)."
        }
      ],
      "related": [
        "types/type-predicates",
        "types/any-and-unknown",
        "types/void-and-never",
        "tags/returns"
      ],
      "sources": [
        {
          "title": "TypeScript 3.7: assertion functions",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "Narrowing",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "generics",
      "slug": "generics",
      "title": "Generics with @template",
      "category": "Generics",
      "jsdoc": "@template T",
      "typescript": "<T>",
      "syntax": [
        {
          "use": "A generic function",
          "jsdoc": "/**\n * @template T\n * @param {T[]} items\n * @returns {T | undefined}\n */",
          "typescript": "function first<T>(items: T[]): T | undefined"
        },
        {
          "use": "Several type parameters",
          "jsdoc": "/** @template K, V, R */",
          "typescript": "<K, V, R>"
        },
        {
          "use": "Using one",
          "jsdoc": "/** @type {Map<K, R>} */",
          "typescript": ": Map<K, R>"
        }
      ],
      "summary": "Generics in JSDoc: declare type parameters with @template T, use T in @param and @returns, and let TypeScript infer it at each call. Generic function examples.",
      "intro": [
        "A generic function works with many types while keeping track of which one it was given. In JSDoc, `@template T` declares the type parameter, and `T` then appears in `@param` and `@returns` like any type. `groupBy(products, (p) => p.category)` returns `Record<string, Product[]>` because `T` is inferred as the product type from the first argument.",
        "The callback is checked against that inferred type, so `(p) => p.category` on products without a `category` is TS2339, as the second example shows."
      ],
      "examples": [
        "types/generics-group-by",
        "types/generics-wrong-callback",
        "types/generics-two-params"
      ],
      "sections": [
        {
          "id": "inside-the-function",
          "heading": "Inside the function",
          "body": [
            "In the body, `T` is unknown in the sense that it could be anything, so you can only do with a `T` what works for every type: store it, return it, pass it on. To read properties from it, give `T` a constraint with `@template {{ id: string }} T`.",
            "A local variable can use the type parameter too: `/** @type {Record<string, T[]>} */ const groups = {};` in the first example."
          ]
        },
        {
          "id": "several-parameters",
          "heading": "Several type parameters",
          "body": [
            "List them with commas, `@template K, V, R`, or give each its own `@template` line. Each one is inferred separately; in the third example `K` and `V` come from the `Map` and `R` from what the callback returns."
          ]
        }
      ],
      "gotchas": [
        "Callers cannot write type arguments in a `.js` file; inference does all the work.",
        "A `@template` tag must be in the same comment as the function's other tags."
      ],
      "faq": [
        {
          "q": "How do I write a generic function in JSDoc?",
          "a": "Add `@template T` to the function's comment and use `T` in its `@param` and `@returns` types. TypeScript infers `T` from the arguments at each call."
        }
      ],
      "related": [
        "tags/template",
        "types/generic-constraints",
        "types/generic-inference",
        "types/generic-classes"
      ],
      "sources": [
        {
          "title": "Generics",
          "url": "https://www.typescriptlang.org/docs/handbook/2/generics.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @template",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "generic-constraints",
      "slug": "generic-constraints",
      "title": "Generic constraints",
      "category": "Generics",
      "jsdoc": "@template {string} K",
      "typescript": "<K extends string>",
      "syntax": [
        {
          "use": "A constraint",
          "jsdoc": "/** @template {{ updatedAt: Date }} T */",
          "typescript": "<T extends { updatedAt: Date }>"
        },
        {
          "use": "Depending on another parameter",
          "jsdoc": "/**\n * @template T\n * @template {keyof T} K\n */",
          "typescript": "<T, K extends keyof T>"
        }
      ],
      "summary": "A constraint limits what a type parameter accepts: @template {string} K is TypeScript's K extends string, written in braces before the name. With examples.",
      "intro": [
        "A constraint says what a type parameter must be assignable to. In JSDoc it goes in braces between `@template` and the name: `@template {{ updatedAt: Date }} T` is TypeScript's `T extends { updatedAt: Date }`. Inside the function you may then use `updatedAt`, and callers must pass something that has it.",
        "Constraints can refer to earlier type parameters. `@template T` followed by `@template {keyof T} K` gives the classic property getter, where the key must be one of the object's own keys (TS2345 for `\"colr\"`, as the first example shows)."
      ],
      "examples": [
        "types/constraint-keyof",
        "types/constraint-shape",
        "types/constraint-first-only"
      ],
      "sections": [
        {
          "id": "one-name-per-constraint",
          "heading": "One name per constraint",
          "body": [
            "A constraint applies only to the first name after it. In `@template {string} K, V`, `K` must be a string and `V` is unconstrained, which is easy to misread. The third example shows the first argument checked against `string` and the second accepting a number. Put each constrained parameter on its own `@template` line."
          ]
        },
        {
          "id": "constraints-and-results",
          "heading": "Constraints keep the specific type",
          "body": [
            "A constrained parameter still infers the caller's full type. `latest(records)` in the second example returns the records' own type, `id` included, not just `{ updatedAt: Date }`. That is the difference from a plain parameter type."
          ]
        }
      ],
      "gotchas": [
        "When an argument does not meet the constraint, the error may be reported on a property of the argument rather than on the call, as with `updatedAt: \"2026-10-20\"` (TS2322).",
        "A constraint and a default can be combined: `@template {string | number} [T=number]`."
      ],
      "faq": [
        {
          "q": "How do I write T extends something in JSDoc?",
          "a": "Put the constraint in braces before the name: `@template {Something} T`."
        }
      ],
      "related": [
        "types/generics",
        "types/generic-defaults",
        "types/keyof",
        "tags/template"
      ],
      "sources": [
        {
          "title": "Generics: generic constraints",
          "url": "https://www.typescriptlang.org/docs/handbook/2/generics.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @template",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "generic-defaults",
      "slug": "generic-defaults",
      "title": "Default type arguments",
      "category": "Generics",
      "jsdoc": "@template [T=string]",
      "typescript": "<T = string>",
      "syntax": [
        {
          "use": "A default",
          "jsdoc": "/** @template [T=string] */",
          "typescript": "<T = string>"
        },
        {
          "use": "Constraint and default",
          "jsdoc": "/** @template {string | number} [T=number] */",
          "typescript": "<T extends string | number = number>"
        }
      ],
      "since": "4.5",
      "summary": "A default type argument, @template [T=string], fills in T when nothing else does. Supported in JSDoc since TypeScript 4.5, on typedefs, classes and functions.",
      "intro": [
        "Brackets with an equals sign give a type parameter a default: `@template [T=string]`. When a type is used without type arguments, `Field` instead of `Field<number>`, or a class is created with nothing to infer from, the default is used. TypeScript 4.5 added defaults to JSDoc.",
        "Defaults are most useful on generic `@typedef`s and classes, where they keep the common case short."
      ],
      "examples": [
        "types/defaults-typedef",
        "types/defaults-class",
        "types/defaults-order"
      ],
      "sections": [
        {
          "id": "classes",
          "heading": "On classes",
          "body": [
            "`new Store()` in the second example has no argument that mentions `T`, so the default applies and `notes` is a `Store<string>`; adding a number is TS2345. Without the default, `T` would be `any` in a `.js` file and nothing would be checked."
          ]
        },
        {
          "id": "order",
          "heading": "Defaults come last",
          "body": [
            "Parameters with defaults must come after the ones without. `@template [K=string], V` is TS2706 (\"Required type parameters may not follow optional type parameters\"), as the third example shows."
          ]
        }
      ],
      "gotchas": [
        "Defaults do not affect inference when there is an argument to infer from: `new Store([1, 2])` with a constructor parameter of type `T[]` would infer `number`.",
        "Before TypeScript 4.5, a JSDoc type parameter could not have a default."
      ],
      "faq": [
        {
          "q": "How do I give a JSDoc type parameter a default?",
          "a": "Put the name in brackets with the default after an equals sign: `@template [T=unknown]`. It works since TypeScript 4.5."
        }
      ],
      "related": [
        "types/generics",
        "types/generic-constraints",
        "types/generic-classes",
        "tags/template"
      ],
      "sources": [
        {
          "title": "TypeScript 4.5: const assertions and default type arguments in JSDoc",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "Generics: generic parameter defaults",
          "url": "https://www.typescriptlang.org/docs/handbook/2/generics.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "generic-classes",
      "slug": "generic-classes",
      "title": "Generic classes",
      "category": "Generics",
      "jsdoc": "@template T",
      "typescript": "class Queue<T>",
      "syntax": [
        {
          "use": "A generic class",
          "jsdoc": "/** @template T */\nclass Queue {\n  /** @param {T} item */\n  push(item) {}\n}",
          "typescript": "class Queue<T> {\n  push(item: T) {}\n}"
        },
        {
          "use": "An instance",
          "jsdoc": "/** @type {Queue<Job>} */\nconst jobs = new Queue();",
          "typescript": "const jobs = new Queue<Job>();"
        }
      ],
      "summary": "A generic class in JSDoc: @template T above the class, T in the members' tags, and the type argument on the variable, since new Queue<T>() is not JavaScript.",
      "intro": [
        "Put `@template T` in the class's JSDoc comment, and `T` is available in every member's tags: field types, `@param`, `@returns`. It is the JavaScript spelling of `class Queue<T>`.",
        "JavaScript cannot write `new Queue<Job>()`, so the type argument comes from one of two places: the variable's `@type {Queue<Job>}`, as in the first example, or the constructor's arguments, which TypeScript infers it from, as in the second."
      ],
      "examples": [
        "types/generic-class-queue",
        "types/generic-class-infer",
        "types/generic-class-wrong"
      ],
      "sections": [
        {
          "id": "without-a-type-argument",
          "heading": "Without a type argument",
          "body": [
            "If neither the variable nor the constructor's arguments say what `T` is, it becomes `any` in a `.js` file, and the instance checks nothing. Give the variable a type, add a default with `@template [T=…]`, or pass something the constructor can infer from."
          ]
        },
        {
          "id": "subclasses",
          "heading": "Subclasses",
          "body": [
            "A subclass of a generic class supplies the type argument with `@extends`: `/** @extends {Queue<string>} */ class SkuQueue extends Queue {}`. A generic subclass combines `@template T` with `@extends {Queue<T>}`."
          ]
        }
      ],
      "gotchas": [
        "Put the field's JSDoc on its own line above it; a comment on the same line as the class's opening brace is not attached to the member.",
        "Static members cannot use the class's type parameter, as in TypeScript."
      ],
      "faq": [
        {
          "q": "How do I make a JavaScript class generic with JSDoc?",
          "a": "Add `@template T` to the class comment and use `T` in the members' JSDoc. Create instances with a typed variable, `/** @type {Queue<string>} */ const q = new Queue();`."
        }
      ],
      "related": [
        "types/generics",
        "types/generic-defaults",
        "tags/extends",
        "tags/template"
      ],
      "sources": [
        {
          "title": "Generics: generic classes",
          "url": "https://www.typescriptlang.org/docs/handbook/2/generics.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @template",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "generic-inference",
      "slug": "generic-inference",
      "title": "Type inference for generics",
      "category": "Generics",
      "jsdoc": "@template const T",
      "typescript": "<const T>",
      "syntax": [
        {
          "use": "Set by the variable's type",
          "jsdoc": "/** @type {{ items: number[] }} */\nconst counts = createStore();",
          "typescript": "const counts = createStore<number>();"
        },
        {
          "use": "Keep literal types",
          "jsdoc": "/** @template const T */",
          "typescript": "<const T>"
        }
      ],
      "summary": "How TypeScript infers @template type parameters in JavaScript, which has no explicit type arguments: from arguments, from the variable's type, and with const T.",
      "intro": [
        "In a `.ts` file you can write `first<string>(rows)`. In a `.js` file you cannot: `first<string>(rows)` is read as two comparisons, `first < string` and `> (rows)`, and tsc reports operator errors (TS2365 and TS2693), as the second example shows. Every type argument in JavaScript is inferred.",
        "TypeScript infers from the arguments first, and from the type the result is assigned to when the arguments say nothing. When neither helps, a type parameter in a `.js` file becomes `any`, which turns checking off for that value."
      ],
      "examples": [
        "types/inference-any-fallback",
        "types/inference-no-type-arguments",
        "types/inference-const-template"
      ],
      "sections": [
        {
          "id": "steering-inference",
          "heading": "Steering inference without type arguments",
          "body": [
            "Type the variable that receives the result: `/** @type {{ items: number[] }} */ const counts = createStore();` makes `T` a `number`, as the first example shows, where the untyped `loose` gets `any`.",
            "Or type an argument: a typed empty array, `/** @type {string[]} */ ([])`, passed to the function gives `T` its type. A cast on the call's result also works, but it only claims the type rather than checking it."
          ]
        },
        {
          "id": "const-type-parameters",
          "heading": "const type parameters",
          "body": [
            "TypeScript 5.0 added `const` type parameters, which infer the narrowest literal types, as if the caller had written `as const`. In JSDoc the modifier goes before the name, `@template const T`, and with TypeScript 5.9 it works as in the third example: `routes.cart` is typed `\"/cart\"`, not `string`."
          ]
        }
      ],
      "gotchas": [
        "The any fallback is specific to JavaScript files; in a `.ts` file the same call infers `unknown`.",
        "A type parameter used only in the return type, as in `createStore`, can never be inferred from arguments. Consider an optional parameter that mentions it, or a default."
      ],
      "faq": [
        {
          "q": "How do I pass a type argument to a generic function in JavaScript?",
          "a": "You cannot write one. Give the variable that receives the result a type with `@type`, type one of the arguments, or give the type parameter a default."
        }
      ],
      "related": [
        "types/generics",
        "types/generic-defaults",
        "tags/template",
        "tags/type"
      ],
      "sources": [
        {
          "title": "Generics: working with generic type variables",
          "url": "https://www.typescriptlang.org/docs/handbook/2/generics.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 5.0: const type parameters",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "Type Checking JavaScript Files: unspecified type parameters default to any",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "union",
      "slug": "union",
      "title": "Union types",
      "category": "Combining types",
      "jsdoc": "{string | number}",
      "typescript": "string | number",
      "since": "2.3",
      "summary": "A union type says a value is one of several types: {string | number} in JSDoc, written as in TypeScript. How to write one, and how to narrow it before use.",
      "intro": [
        "A union type is a list of types separated by `|`, and a value of that type can be any one of them. In JSDoc the union goes inside the braces exactly as you would write it in TypeScript: `@param {string | number} id`.",
        "Until you narrow a union, TypeScript only lets you use what every member has in common. A `typeof`, `instanceof`, `in` or equality check narrows the value to the matching members inside that branch."
      ],
      "examples": [
        "types/union-narrowing",
        "types/union-no-narrowing",
        "types/union-literal"
      ],
      "sections": [
        {
          "id": "syntax",
          "heading": "Writing a union",
          "body": [
            "Separate the members with `|`: `{string | number}`, `{\"small\" | \"medium\" | \"large\"}`, `{User | null}`. The older JSDoc style with parentheses, `{(string|number)}`, means the same thing and TypeScript accepts it.",
            "For a union you use more than once, give it a name with `@typedef`: `/** @typedef {\"small\" | \"medium\" | \"large\"} Size */`. The name works anywhere a type does, and other modules can use it through an import type."
          ]
        },
        {
          "id": "narrowing",
          "heading": "Narrowing",
          "body": [
            "Narrowing is ordinary JavaScript. The runtime checks you would write anyway are the ones TypeScript reads to work out which member you have:"
          ],
          "list": [
            "`typeof x === \"string\"` for primitives",
            "`x instanceof Date` for classes",
            "`Array.isArray(x)` for arrays",
            "`\"name\" in x` for objects with different properties",
            "`x === null` or `x != null` for nullable values",
            "a literal property every member has, such as `kind: \"circle\"`, which makes a discriminated union"
          ]
        },
        {
          "id": "literal-unions",
          "heading": "Unions of literals",
          "body": [
            "A union of string literals is the usual JavaScript stand-in for an enum. The checker rejects any other string at the call site (TS2345 in the third example), and editors offer the allowed values as completions while you type the argument."
          ]
        }
      ],
      "gotchas": [
        "Calling a method that only one member has is an error until you narrow: `toUpperCase` exists on `string` but not on `number`, so `id.toUpperCase()` fails with TS2339.",
        "`{?string}` and `{string | null}` mean the same thing in TypeScript. The second is clearer, and it is how the checker prints the type in its messages.",
        "With `strict` (or `strictNullChecks`) off, `null` and `undefined` are part of every type, so writing `{string | null}` adds no protection."
      ],
      "faq": [
        {
          "q": "How do I write an optional or nullable union in JSDoc?",
          "a": "Add `null` or `undefined` as a member: `{string | null}`. For an optional parameter, put its name in square brackets, `@param {string} [label]`; inside the function its type is then `string | undefined`."
        }
      ],
      "related": [
        "tags/type",
        "types/literal-types",
        "types/discriminated-unions",
        "types/intersection",
        "types/type-predicates",
        "guides/javascript-runtime-types-vs-annotations"
      ],
      "sources": [
        {
          "title": "Everyday Types: Union Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Narrowing",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "intersection",
      "slug": "intersection",
      "title": "Intersection types",
      "category": "Combining types",
      "jsdoc": "{Product & Stored}",
      "typescript": "Product & Stored",
      "syntax": [
        {
          "use": "Two types at once",
          "jsdoc": "/** @typedef {Product & Stored} StoredProduct */",
          "typescript": "type StoredProduct = Product & Stored;"
        },
        {
          "use": "Adding a property inline",
          "jsdoc": "/** @param {Product & { discount: number }} item */",
          "typescript": "(item: Product & { discount: number })"
        }
      ],
      "since": null,
      "summary": "An intersection type, A & B, is a value that is both: every property of A and of B. Written the same in JSDoc; the usual way to extend a @typedef.",
      "intro": [
        "An intersection `{Product & Stored}` describes a value that has everything `Product` has and everything `Stored` has. It is how JSDoc types are combined and extended: a `@typedef` cannot use `extends`, but `@typedef {Base & { extra: string }} Extended` does the same job.",
        "A value of an intersection type must satisfy every part. An object literal missing the `id` that one part requires fails (TS2322, with the missing property named underneath), as the second example shows."
      ],
      "examples": [
        "types/intersection-basic",
        "types/intersection-missing",
        "types/intersection-conflict"
      ],
      "sections": [
        {
          "id": "union-or-intersection",
          "heading": "Union or intersection?",
          "body": [
            "A union `A | B` is one or the other: you may only use what they share until you narrow it. An intersection `A & B` is both at once: you may use everything from either. For object types the intersection has more properties and accepts fewer values."
          ]
        },
        {
          "id": "conflicts",
          "heading": "Conflicting properties",
          "body": [
            "When both parts declare the same property with incompatible types, the property's type is the intersection of the two, which may be `never`. `{ id: string } & { id: number }` makes `id` impossible to set, and the error says a string is not assignable to `never`, as the third example shows."
          ]
        }
      ],
      "gotchas": [
        "Intersections of two different primitive types are `never`: `string & number` has no values.",
        "Error messages show the expanded intersection, which can be long; a `@typedef` name keeps them readable."
      ],
      "faq": [
        {
          "q": "How do I extend a @typedef in JSDoc?",
          "a": "Intersect it with the extra properties: `/** @typedef {Product & { id: string }} StoredProduct */`."
        }
      ],
      "related": [
        "types/union",
        "tags/typedef",
        "types/object-shapes",
        "types/discriminated-unions"
      ],
      "sources": [
        {
          "title": "Object Types: intersection types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Everyday Types: type aliases and interfaces",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "discriminated-unions",
      "slug": "discriminated-unions",
      "title": "Discriminated unions",
      "category": "Combining types",
      "jsdoc": "{{ kind: \"circle\", radius: number } | { kind: \"square\", side: number }}",
      "typescript": "{ kind: \"circle\"; radius: number } | { kind: \"square\"; side: number }",
      "syntax": [
        {
          "use": "A tagged union",
          "jsdoc": "/** @typedef {{ kind: \"circle\", radius: number } | { kind: \"square\", side: number }} Shape */",
          "typescript": "type Shape = { kind: \"circle\"; radius: number } | { kind: \"square\"; side: number };"
        },
        {
          "use": "A result type",
          "jsdoc": "/**\n * @template T\n * @typedef {{ ok: true, data: T } | { ok: false, error: string }} Result\n */",
          "typescript": "type Result<T> = { ok: true; data: T } | { ok: false; error: string };"
        }
      ],
      "since": null,
      "summary": "A discriminated union is a union of object types sharing a literal property such as kind; checking it narrows the value. JSDoc syntax and examples.",
      "intro": [
        "A discriminated union is a union of object types that all have one property with a different literal value in each: `kind: \"circle\"` or `kind: \"square\"`. Testing that property, in a `switch` or an `if`, tells TypeScript which member you have, and inside that branch only its properties are available.",
        "It is the type-safe way to model data that comes in variants: shapes, events, API results, the states of a request. A property that belongs to another variant is TS2339 in the wrong branch, as the second example shows."
      ],
      "examples": [
        "types/discriminated-shapes",
        "types/discriminated-wrong-member",
        "types/discriminated-result"
      ],
      "sections": [
        {
          "id": "writing-them",
          "heading": "Writing them in JSDoc",
          "body": [
            "Write the union in a `@typedef`. Long unions can span several lines inside the comment, as in the first example; the leading `|` on each continuation line is allowed. Each member is an object type with the discriminant as a literal type.",
            "For a generic result type, combine with `@template`: `{ ok: true, data: T } | { ok: false, error: string }` makes callers check `result.ok` before they can read `data`, as the third example does."
          ]
        },
        {
          "id": "exhaustiveness",
          "heading": "Handling every case",
          "body": [
            "The `area` function in the first example has no `default` and no final `return`, yet TypeScript accepts its `@returns {number}`: the `switch` covers every `kind`, so the end of the function is unreachable. Adding a fourth shape without a `case` makes that an error. A `default` that passes the value to a `never` parameter makes the check explicit."
          ]
        }
      ],
      "gotchas": [
        "The discriminant must be a literal type in each member. If one member has `kind: string`, nothing narrows.",
        "Every member needs the discriminant property: if one member lacks `kind`, reading `shape.kind` before narrowing is already an error."
      ],
      "faq": [
        {
          "q": "How do I write a tagged union in JSDoc?",
          "a": "As a `@typedef` of object types that each have the same property with a different literal value, for example `{{ type: \"click\", x: number } | { type: \"key\", key: string }}`."
        }
      ],
      "related": [
        "types/union",
        "types/literal-types",
        "types/void-and-never",
        "tags/typedef"
      ],
      "sources": [
        {
          "title": "Narrowing: discriminated unions",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Everyday Types: union types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "keyof",
      "slug": "keyof",
      "title": "keyof",
      "category": "Combining types",
      "jsdoc": "{keyof Product}",
      "typescript": "keyof Product",
      "syntax": [
        {
          "use": "The keys of a type",
          "jsdoc": "/** @param {keyof Product} field */",
          "typescript": "(field: keyof Product)"
        },
        {
          "use": "The keys of a value",
          "jsdoc": "/** @typedef {keyof typeof LABELS} Column */",
          "typescript": "type Column = keyof typeof LABELS;"
        }
      ],
      "since": null,
      "summary": "keyof Product is the union of Product's property names. Use it in JSDoc for parameters that take a field name, and keyof typeof for the keys of an object value.",
      "intro": [
        "`keyof T` is the union of the property names of `T`. For `{ sku: string, name: string, price: number }`, `keyof` gives `\"sku\" | \"name\" | \"price\"`, so a parameter typed `{keyof Product}` accepts only those strings and rejects a typo like `\"prise\"` (TS2345).",
        "For the keys of an object you have as a value, not as a type, combine it with `typeof`: `{keyof typeof LABELS}`."
      ],
      "examples": [
        "types/keyof-sort",
        "types/keyof-typo",
        "types/keyof-typeof"
      ],
      "sections": [
        {
          "id": "with-generics",
          "heading": "With generics",
          "body": [
            "`keyof` is most useful as a constraint: `@template T` with `@template {keyof T} K` lets a function take an object and one of its keys, and return `T[K]`, the type of that property. The [generic constraints](/types/generic-constraints/) page has that example."
          ]
        },
        {
          "id": "index-signatures",
          "heading": "Types with index signatures",
          "body": [
            "For `Record<string, number>`, `keyof` is `string` (and `number`, since numeric keys are strings in JavaScript), so it no longer limits anything. `keyof` is precise only for types with known property names."
          ]
        }
      ],
      "gotchas": [
        "`keyof` of a union gives only the keys every member shares.",
        "Inside the function, `a[field]` has the union of all property types; narrow it or use the generic form when you need the exact one."
      ],
      "faq": [
        {
          "q": "How do I accept only the property names of an object type in JSDoc?",
          "a": "Type the parameter as `{keyof YourType}`. For an object value, use `{keyof typeof yourObject}`."
        }
      ],
      "related": [
        "types/typeof",
        "types/indexed-access",
        "types/generic-constraints",
        "types/mapped-types"
      ],
      "sources": [
        {
          "title": "Keyof Type Operator",
          "url": "https://www.typescriptlang.org/docs/handbook/2/keyof-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "typeof",
      "slug": "typeof",
      "title": "typeof in types",
      "category": "Combining types",
      "jsdoc": "{typeof defaults}",
      "typescript": "typeof defaults",
      "syntax": [
        {
          "use": "The type of a value",
          "jsdoc": "/** @param {Partial<typeof defaults>} overrides */",
          "typescript": "(overrides: Partial<typeof defaults>)"
        },
        {
          "use": "The type of a function",
          "jsdoc": "/** @type {typeof formatPrice} */",
          "typescript": ": typeof formatPrice"
        }
      ],
      "since": null,
      "summary": "typeof in a JSDoc type gives you the type of a value, such as a config object or a function, without writing it twice. How it differs from JavaScript's typeof.",
      "intro": [
        "Inside a type, `typeof name` means \"the type of the value called `name`\". `{Partial<typeof defaults>}` reuses the shape of a settings object as the type of its overrides, so adding a setting to `defaults` updates the parameter type too. A wrong value type in the overrides is still TS2322, as the first example shows.",
        "This is a type operator, not JavaScript's run-time `typeof`, which returns a string such as `\"object\"`. The two share a keyword and nothing else."
      ],
      "examples": [
        "types/typeof-config",
        "types/typeof-function",
        "types/typeof-not-a-value"
      ],
      "sections": [
        {
          "id": "values-not-types",
          "heading": "It takes a value",
          "body": [
            "`typeof` must be followed by a value. A `@typedef` name is a type, so `{typeof Settings}` is TS2693 (\"'Settings' only refers to a type, but is being used as a value here\"), as the third example shows. A class name works either way: `{Cart}` is the instance type, `{typeof Cart}` the class itself with its constructor and static members."
          ]
        },
        {
          "id": "value-names-in-javascript",
          "heading": "Value names without typeof in a .js file",
          "body": [
            "In a `.js` file TypeScript also accepts a value's name in a JSDoc type and uses the value's type: `{defaults}` means the same as `{typeof defaults}`, and `ReturnType<createCart>` works without the `typeof`. A `.ts` file rejects both (TS2749). Writing `typeof` keeps the JSDoc valid TypeScript and makes the intent clear; the [`ReturnType` page](/types/returntype/) shows the difference side by side."
          ]
        }
      ],
      "gotchas": [
        "`typeof` captures the widened type of a `let` or a mutable object property (`string`, not `\"USD\"`). Use a `const` assertion on the value to keep literal types.",
        "`typeof import(\"./config.js\")` gives the type of a whole module."
      ],
      "faq": [
        {
          "q": "How do I get the type of a variable in JSDoc?",
          "a": "Write `typeof` and the variable's name inside the braces: `/** @type {typeof defaults} */`."
        }
      ],
      "related": [
        "types/keyof",
        "types/returntype",
        "types/partial",
        "tags/type"
      ],
      "sources": [
        {
          "title": "Typeof Type Operator",
          "url": "https://www.typescriptlang.org/docs/handbook/2/typeof-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: import types and typeof",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "indexed-access",
      "slug": "indexed-access",
      "title": "Indexed access types",
      "category": "Combining types",
      "jsdoc": "{Order[\"status\"]}",
      "typescript": "Order[\"status\"]",
      "syntax": [
        {
          "use": "One property's type",
          "jsdoc": "/** @typedef {Order[\"status\"]} OrderStatus */",
          "typescript": "type OrderStatus = Order[\"status\"];"
        },
        {
          "use": "An array's element type",
          "jsdoc": "/** @typedef {Order[\"lines\"][number]} OrderLine */",
          "typescript": "type OrderLine = Order[\"lines\"][number];"
        },
        {
          "use": "Elements of a const array",
          "jsdoc": "/** @typedef {(typeof SIZES)[number]} Size */",
          "typescript": "type Size = (typeof SIZES)[number];"
        }
      ],
      "since": null,
      "summary": "An indexed access type, Order[\"status\"], is the type of one property of another type. In JSDoc it looks the same; [number] gives an array's element type.",
      "intro": [
        "`Order[\"status\"]` is the type of the `status` property of `Order`. It lets a function take exactly what a property holds without repeating its definition, so the two stay in step when `Order` changes.",
        "Indexing with `number` gives the element type of an array: `Order[\"lines\"][number]` is the type of one line. Combined with a `const` assertion, `(typeof SIZES)[number]` turns an array of values into a union type."
      ],
      "examples": [
        "types/indexed-order",
        "types/indexed-typo",
        "types/indexed-const-array"
      ],
      "sections": [
        {
          "id": "checked-keys",
          "heading": "The key is checked",
          "body": [
            "The index must be a key of the type. `Order[\"stauts\"]` is TS2339, reported on the JSDoc line, as the second example shows. That makes indexed access safer than copying a property's type by hand."
          ]
        },
        {
          "id": "unions-of-values",
          "heading": "Values and their type from one list",
          "body": [
            "`const SIZES = /** @type {const} */ ([\"S\", \"M\", \"L\", \"XL\"])` keeps the strings as literals, and `(typeof SIZES)[number]` is `\"S\" | \"M\" | \"L\" | \"XL\"`. The array is used at run time (for a dropdown, say) and the type comes from it, so the list exists once."
          ]
        }
      ],
      "gotchas": [
        "The property name goes in quotes: `Order[\"status\"]`. `Order.status` is not a type.",
        "Indexing with a union, `Order[\"id\" | \"status\"]`, gives the union of those properties' types."
      ],
      "faq": [
        {
          "q": "How do I get the type of an array element in JSDoc?",
          "a": "Index the array type with `number`: `{Order[\"lines\"][number]}`, or `{(typeof items)[number]}` for an array value."
        }
      ],
      "related": [
        "types/keyof",
        "types/typeof",
        "types/arrays",
        "types/const-assertions"
      ],
      "sources": [
        {
          "title": "Indexed Access Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "conditional-types",
      "slug": "conditional-types",
      "title": "Conditional types",
      "category": "Combining types",
      "jsdoc": "{T extends string ? \"text\" : \"other\"}",
      "typescript": "T extends string ? \"text\" : \"other\"",
      "syntax": [
        {
          "use": "A conditional type",
          "jsdoc": "/**\n * @template T\n * @typedef {T extends string ? \"text\" : \"other\"} Kind\n */",
          "typescript": "type Kind<T> = T extends string ? \"text\" : \"other\";"
        },
        {
          "use": "With infer",
          "jsdoc": "/**\n * @template T\n * @typedef {T extends Promise<infer U> ? U : T} Unwrapped\n */",
          "typescript": "type Unwrapped<T> = T extends Promise<infer U> ? U : T;"
        }
      ],
      "since": null,
      "summary": "A conditional type chooses between two types by testing a third: T extends string ? A : B. In JSDoc it lives in a generic @typedef. infer and unions explained.",
      "intro": [
        "A conditional type, `T extends string ? \"text\" : \"other\"`, checks whether `T` is assignable to `string` and becomes the first type if it is and the second if not. In JSDoc it goes in a `@typedef` with `@template T`, and it is written exactly as in TypeScript. TypeScript added conditional types in version 2.8.",
        "Most code uses conditional types through the built-in utility types (`Exclude`, `NonNullable`, `ReturnType`, `Awaited`) rather than writing them. Reading one is still useful, because error messages and library types show them."
      ],
      "examples": [
        "types/conditional-kind",
        "types/conditional-wrong",
        "types/conditional-distributive"
      ],
      "sections": [
        {
          "id": "infer",
          "heading": "infer",
          "body": [
            "`infer U` inside the `extends` clause names a part of the type for use in the true branch: `T extends Promise<infer U> ? U : T` pulls the resolved type out of a promise. That is the idea behind `Awaited` and `ReturnType`."
          ]
        },
        {
          "id": "distribution",
          "heading": "Conditional types and unions",
          "body": [
            "When the checked type is a bare type parameter and the argument is a union, the condition applies to each member separately and the results are joined. `Present<string | null | undefined>` in the third example becomes `string`, because the `null` and `undefined` members map to `never`. This is how `NonNullable` and `Exclude` work."
          ]
        }
      ],
      "gotchas": [
        "Wrap the type parameter in brackets, `[T] extends [string]`, to test a union as a whole instead of member by member.",
        "Deeply nested conditional types slow down checking and produce long messages; prefer a built-in utility type when one fits."
      ],
      "faq": [
        {
          "q": "Can I write conditional types in JSDoc?",
          "a": "Yes. Put them in a `@typedef` with the `@template` parameters they use; the syntax inside the braces is TypeScript's."
        }
      ],
      "related": [
        "types/exclude-and-extract",
        "types/nonnullable",
        "types/awaited",
        "tags/template"
      ],
      "sources": [
        {
          "title": "Conditional Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/conditional-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 2.8: conditional types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "mapped-types",
      "slug": "mapped-types",
      "title": "Mapped types",
      "category": "Combining types",
      "jsdoc": "{{ [K in keyof T]?: string }}",
      "typescript": "{ [K in keyof T]?: string }",
      "syntax": [
        {
          "use": "One property per key",
          "jsdoc": "/**\n * @template T\n * @typedef {{ [K in keyof T]?: string }} FormErrors\n */",
          "typescript": "type FormErrors<T> = { [K in keyof T]?: string };"
        },
        {
          "use": "Renaming keys",
          "jsdoc": "{{ [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] }}",
          "typescript": "{ [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] }"
        }
      ],
      "since": null,
      "summary": "A mapped type builds an object type with one property per key of another: { [K in keyof T]?: string }. Writing mapped types in JSDoc, with key renaming.",
      "intro": [
        "A mapped type creates an object type by going through a set of keys: `{ [K in keyof T]?: string }` has one optional string property for every property of `T`. A form's error messages, a set of loading flags or a map of change handlers can follow the shape of the data they belong to, as in the first example.",
        "In JSDoc, mapped types live in a `@typedef` with `@template`. Like other object types, they need the double braces of a type literal inside the tag."
      ],
      "examples": [
        "types/mapped-errors",
        "types/mapped-extra-key",
        "types/mapped-getters"
      ],
      "sections": [
        {
          "id": "modifiers",
          "heading": "Modifiers",
          "body": [
            "`?` makes every property optional and `readonly` makes every property read-only; `-?` and `-readonly` remove them. `Partial<T>`, `Required<T>` and `Readonly<T>` are mapped types with exactly these modifiers."
          ]
        },
        {
          "id": "key-remapping",
          "heading": "Renaming keys with as",
          "body": [
            "An `as` clause renames each key, often with a template literal type: `` [K in keyof T as `get${Capitalize<string & K>}`] `` turns `sku` into `getSku`, as the third example shows. Mapping a key to `never` drops it. TypeScript added key remapping in version 4.1."
          ]
        }
      ],
      "gotchas": [
        "The mapped type keeps the source's keys exactly, so a misspelled key in an object literal is an excess property ([TS2561](/errors/ts2561/) with a suggestion, as in the second example).",
        "`string & K` in the renaming example is needed because `keyof T` can include number and symbol keys, which `Capitalize` does not accept."
      ],
      "faq": [
        {
          "q": "Can I use mapped types in JSDoc?",
          "a": "Yes, inside a type literal in a `@typedef`: `/** @template T @typedef {{ [K in keyof T]: boolean }} Flags */`, with the tags on separate lines if you prefer."
        }
      ],
      "related": [
        "types/keyof",
        "types/partial",
        "types/template-literal-types",
        "tags/template"
      ],
      "sources": [
        {
          "title": "Mapped Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/mapped-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 4.1: key remapping in mapped types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "template-literal-types",
      "slug": "template-literal-types",
      "title": "Template literal types",
      "category": "Combining types",
      "jsdoc": "{`${number}px`}",
      "typescript": "`${number}px`",
      "syntax": [
        {
          "use": "A pattern",
          "jsdoc": "/** @typedef {`${number}px`} Pixels */",
          "typescript": "type Pixels = `${number}px`;"
        },
        {
          "use": "Built from a union",
          "jsdoc": "/** @typedef {`on${Capitalize<Interaction>}`} HandlerName */",
          "typescript": "type HandlerName = `on${Capitalize<Interaction>}`;"
        }
      ],
      "since": null,
      "summary": "Template literal types describe string patterns, such as ${number}px or on${Capitalize<Interaction>}. They work inside JSDoc braces, backticks included.",
      "intro": [
        "A template literal type uses the syntax of a JavaScript template string to describe a set of strings: `` `${number}px` `` accepts `\"320px\"` and rejects `\"20em\"` (TS2345). TypeScript added them in version 4.1, and they work inside JSDoc braces unchanged.",
        "Placeholders can hold unions, and every combination is produced: `` `${\"TEE\" | \"MUG\"}-${number}` `` accepts `\"TEE-01\"` and `\"MUG-7\"` but not `\"tee-01\"`, as the third example shows."
      ],
      "examples": [
        "types/template-literal-px",
        "types/template-literal-handlers",
        "types/template-literal-sku"
      ],
      "sections": [
        {
          "id": "string-helpers",
          "heading": "Changing case",
          "body": [
            "The built-in `Uppercase`, `Lowercase`, `Capitalize` and `Uncapitalize` types change the case of string literal types. `` `on${Capitalize<Interaction>}` `` turns `\"click\" | \"hover\"` into `\"onClick\" | \"onHover\"`, which keeps handler names and event names in step."
          ]
        }
      ],
      "gotchas": [
        "A plain `string` value does not match a pattern even if its contents would; the check needs a literal or a value already typed with the pattern.",
        "Large unions in several placeholders multiply: three placeholders of ten members each make a thousand strings, which slows checking."
      ],
      "faq": [
        {
          "q": "Do template literal types work in JSDoc?",
          "a": "Yes. Write them with backticks inside the braces, exactly as in TypeScript: `` /** @type {`${number}px`} */ ``."
        }
      ],
      "related": [
        "types/literal-types",
        "types/union",
        "types/mapped-types",
        "types/other-utility-types"
      ],
      "sources": [
        {
          "title": "Template Literal Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 4.1: template literal types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "partial",
      "slug": "partial",
      "title": "Partial<T>",
      "category": "Utility types",
      "jsdoc": "{Partial<Product>}",
      "typescript": "Partial<Product>",
      "since": null,
      "summary": "Partial<T> makes every property of T optional. Use it in JSDoc for update payloads, options and fixtures; the types of the properties present stay checked.",
      "intro": [
        "`Partial<Product>` is `Product` with every property optional. It fits values that hold some of an object's fields: the changes in an update, user options merged over defaults, a fixture that fills in the rest. TypeScript has had it since version 2.1.",
        "Only the presence of properties is relaxed. A property that is there must still have the right type (TS2322 for `price: \"17.50\"`), and an extra property in an object literal is still an error."
      ],
      "examples": [
        "types/partial-update",
        "types/partial-wrong-type",
        "types/partial-reading"
      ],
      "sections": [
        {
          "id": "reading",
          "heading": "Reading a Partial",
          "body": [
            "Every property of a `Partial` may be `undefined`, so reading one requires a check: `changes.price.toFixed(2)` is TS18048, as the third example shows. Merging with a complete object, `{ ...product, ...changes }`, gives back a full `Product`."
          ]
        }
      ],
      "gotchas": [
        "`Partial` is shallow: nested objects keep their required properties.",
        "With `exactOptionalPropertyTypes`, `Partial<Product>` does not accept `{ price: undefined }`; without it, it does, and the spread then writes `undefined` over the price."
      ],
      "faq": [
        {
          "q": "How do I make all properties optional in JSDoc?",
          "a": "Wrap the type: `@param {Partial<Product>} changes`."
        }
      ],
      "related": [
        "types/required",
        "types/readonly",
        "types/pick",
        "types/mapped-types"
      ],
      "sources": [
        {
          "title": "Utility Types: Partial<Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "required",
      "slug": "required",
      "title": "Required<T>",
      "category": "Utility types",
      "jsdoc": "{Required<PriceOptions>}",
      "typescript": "Required<PriceOptions>",
      "since": "2.8",
      "summary": "Required<T> makes every property of T mandatory, the reverse of Partial. Useful in JSDoc for options after their defaults are filled in. Examples and errors.",
      "intro": [
        "`Required<PriceOptions>` is `PriceOptions` with the `?` removed from every property. It describes an options object after defaults have been applied: callers pass a partial object, and the code inside works with a complete one.",
        "A value missing any property is an error (TS2741, \"Property 'digits' is missing…\"), as the second example shows."
      ],
      "examples": [
        "types/required-options",
        "types/required-missing"
      ],
      "sections": [
        {
          "id": "defaults-pattern",
          "heading": "The defaults pattern",
          "body": [
            "Declare the defaults as `Required<Options>` so TypeScript makes you supply every one, then spread the caller's options over them. The result can be typed `Required<Options>` too, and inside the function no property needs an `undefined` check."
          ]
        }
      ],
      "gotchas": [
        "With `exactOptionalPropertyTypes` on, `Required` removes the `?` but keeps an `undefined` written into the type: `digits?: number | undefined` becomes `digits: number | undefined`. With it off, the result is `digits: number`.",
        "Like `Partial`, it is shallow."
      ],
      "faq": [
        {
          "q": "What is the opposite of Partial<T>?",
          "a": "`Required<T>`, which makes every property mandatory."
        }
      ],
      "related": [
        "types/partial",
        "types/readonly",
        "types/optional-parameters",
        "types/object-shapes"
      ],
      "sources": [
        {
          "title": "Utility Types: Required<Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 2.8: improved control over mapped type modifiers",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "readonly",
      "slug": "readonly",
      "title": "Readonly<T>",
      "category": "Utility types",
      "jsdoc": "{Readonly<Product>}",
      "typescript": "Readonly<Product>",
      "since": null,
      "summary": "Readonly<T> makes every property of T read-only, so assignments are errors. Use it in JSDoc to promise a function will not modify an object. It is shallow.",
      "intro": [
        "`Readonly<Product>` is `Product` with every property marked `readonly`. Assigning to one is TS2540 (\"Cannot assign to 'price' because it is a read-only property\"), as the first example shows. On a parameter, it tells callers that the function will not change the object they pass.",
        "TypeScript has had `Readonly` since version 2.1. It exists only for TypeScript's checker; `Object.freeze` is the run-time counterpart and returns a `Readonly` type."
      ],
      "examples": [
        "types/readonly-utility",
        "types/readonly-shallow"
      ],
      "sections": [
        {
          "id": "shallow",
          "heading": "Only one level deep",
          "body": [
            "`Readonly` covers the object's own properties, not the objects they point to. In the second example `product.tags.push(\"sale\")` passes, because `tags` itself was not reassigned. Type nested arrays as `readonly string[]` when they should not change either."
          ]
        }
      ],
      "gotchas": [
        "A `Readonly<T>` value can be passed where a plain `T` is expected; TypeScript does not treat `readonly` properties as incompatible with mutable ones in assignments.",
        "For arrays, `Readonly<string[]>` is the same as `readonly string[]`."
      ],
      "faq": [
        {
          "q": "How do I make an object parameter read-only in JSDoc?",
          "a": "Type it `@param {Readonly<Product>} product`. Nested arrays and objects need their own `readonly` types."
        }
      ],
      "related": [
        "types/readonly-arrays",
        "tags/readonly",
        "types/partial",
        "errors/ts2540",
        "types/const-assertions"
      ],
      "sources": [
        {
          "title": "Utility Types: Readonly<Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "pick",
      "slug": "pick",
      "title": "Pick<T, K>",
      "category": "Utility types",
      "jsdoc": "{Pick<Product, \"sku\" | \"name\">}",
      "typescript": "Pick<Product, \"sku\" | \"name\">",
      "since": null,
      "summary": "Pick<T, K> builds a type with only the properties K of T. In JSDoc it names smaller views of a type, such as a card, and checks that the keys exist.",
      "intro": [
        "`Pick<Product, \"sku\" | \"name\" | \"price\">` is a type with just those three properties, typed as in `Product`. It names a smaller view of a larger type, such as what a product card shows, so the view changes when the source does.",
        "The keys are checked: `Pick<Product, \"sku\" | \"colr\">` is TS2344 (\"Type … does not satisfy the constraint 'keyof Product'\"), reported on the `@typedef` line. TypeScript has had `Pick` since version 2.1."
      ],
      "examples": [
        "types/pick-summary",
        "types/pick-unknown-key"
      ],
      "sections": [
        {
          "id": "pick-or-omit",
          "heading": "Pick or Omit?",
          "body": [
            "Pick names what to keep; `Omit` names what to drop. Use `Pick` when the view is small and stable, `Omit` when you want everything except a few fields. Unlike `Pick`, `Omit` does not check its keys."
          ]
        }
      ],
      "gotchas": [
        "Assigning a full `Product` to a `Pick` type is fine; only object literals are checked for extra properties.",
        "A picked property keeps its optional and `readonly` modifiers."
      ],
      "faq": [
        {
          "q": "How do I make a type with only some properties of another in JSDoc?",
          "a": "`/** @typedef {Pick<Product, \"sku\" | \"name\">} ProductCard */`."
        }
      ],
      "related": [
        "types/omit",
        "types/partial",
        "types/keyof",
        "tags/typedef"
      ],
      "sources": [
        {
          "title": "Utility Types: Pick<Type, Keys>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "omit",
      "slug": "omit",
      "title": "Omit<T, K>",
      "category": "Utility types",
      "jsdoc": "{Omit<Product, \"id\">}",
      "typescript": "Omit<Product, \"id\">",
      "since": "3.5",
      "summary": "Omit<T, K> is T without the properties K, such as a product before it has an id. How to use it in JSDoc, and why a misspelled key is not caught.",
      "intro": [
        "`Omit<Product, \"id\">` has every property of `Product` except `id`. It is the natural type for data before the server or the database adds fields: a draft passed to `create()`, which returns the full `Product`.",
        "Passing the omitted property in an object literal is TS2353, as the first example shows, so callers cannot set an `id` that `create()` will overwrite. TypeScript added `Omit` in version 3.5."
      ],
      "examples": [
        "types/omit-draft",
        "types/omit-unchecked-key"
      ],
      "sections": [
        {
          "id": "unchecked-keys",
          "heading": "The keys are not checked",
          "body": [
            "`Omit` accepts any key, not only keys of the type, so `Omit<Product, \"iid\">` is not an error. It simply removes nothing, as the second example shows. When the key list matters, use `Pick` with the keys to keep, or a typedef whose key parameter is constrained (`@template T`, `@template {keyof T} K`, `@typedef {Omit<T, K>} StrictOmit`), which rejects a misspelled key with TS2344."
          ]
        }
      ],
      "gotchas": [
        "`Omit` on a union does not distribute: `Omit<A | B, \"id\">` keeps only the properties A and B share. Write a conditional type to omit from each member separately.",
        "The result is a new object type, so hovers show the expanded property list rather than the original name."
      ],
      "faq": [
        {
          "q": "How do I remove a property from a type in JSDoc?",
          "a": "`/** @typedef {Omit<Product, \"id\" | \"createdAt\">} ProductDraft */`."
        }
      ],
      "related": [
        "types/pick",
        "types/exclude-and-extract",
        "types/partial",
        "tags/typedef"
      ],
      "sources": [
        {
          "title": "Utility Types: Omit<Type, Keys>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 3.5: the Omit helper type",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "exclude-and-extract",
      "slug": "exclude-and-extract",
      "title": "Exclude<T, U> and Extract<T, U>",
      "category": "Utility types",
      "jsdoc": "{Exclude<Status, \"deleted\">}",
      "typescript": "Exclude<Status, \"deleted\">",
      "syntax": [
        {
          "use": "Remove members",
          "jsdoc": "/** @typedef {Exclude<Status, \"deleted\">} VisibleStatus */",
          "typescript": "type VisibleStatus = Exclude<Status, \"deleted\">;"
        },
        {
          "use": "Keep members",
          "jsdoc": "/** @typedef {Extract<Status, \"draft\" | \"live\">} EditableStatus */",
          "typescript": "type EditableStatus = Extract<Status, \"draft\" | \"live\">;"
        },
        {
          "use": "Pick a union member by shape",
          "jsdoc": "/** @typedef {Extract<UiEvent, { type: \"click\" }>} ClickEvent */",
          "typescript": "type ClickEvent = Extract<UiEvent, { type: \"click\" }>;"
        }
      ],
      "since": "2.8",
      "summary": "Exclude<T, U> removes union members assignable to U; Extract<T, U> keeps them. Use them in JSDoc to filter literal unions and discriminated unions. Examples.",
      "intro": [
        "`Exclude<Status, \"deleted\">` is the union `Status` without the member `\"deleted\"`; `Extract<Status, \"draft\" | \"live\">` keeps only those two. They filter union types, member by member; TypeScript 2.8 added them along with conditional types.",
        "`Extract` with an object shape picks members of a discriminated union: `Extract<UiEvent, { type: \"click\" }>` is the click event type, with its `x` and `y`."
      ],
      "examples": [
        "types/exclude-extract",
        "types/exclude-rejects"
      ],
      "sections": [
        {
          "id": "unions-only",
          "heading": "They work on unions",
          "body": [
            "Both are distributive conditional types, so they act on each member of a union. They are not for object properties: to drop a property from an object type, use `Omit`; to keep some, `Pick`."
          ]
        }
      ],
      "gotchas": [
        "Neither checks that `U` matches anything. `Exclude<Status, \"delted\">` silently removes nothing.",
        "`NonNullable<T>` is the special case `Exclude<T, null | undefined>`."
      ],
      "faq": [
        {
          "q": "What is the difference between Exclude and Omit?",
          "a": "`Exclude` removes members from a union type; `Omit` removes properties from an object type."
        }
      ],
      "related": [
        "types/union",
        "types/discriminated-unions",
        "types/nonnullable",
        "types/omit"
      ],
      "sources": [
        {
          "title": "Utility Types: Exclude and Extract",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 2.8: predefined conditional types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "nonnullable",
      "slug": "nonnullable",
      "title": "NonNullable<T>",
      "category": "Utility types",
      "jsdoc": "{NonNullable<Product[\"discount\"]>}",
      "typescript": "NonNullable<Product[\"discount\"]>",
      "since": "2.8",
      "summary": "NonNullable<T> removes null and undefined from a type. Use it in JSDoc for the value after a check or a default, and in helpers that filter out empty values.",
      "intro": [
        "`NonNullable<T>` is `T` without `null` and `undefined`. `NonNullable<Product[\"discount\"]>` is `number` when the discount property is `number | null | undefined`, which is the right type for the value after `?? 0`.",
        "Assigning `null` to it is an error (TS2322), as the first example shows. TypeScript 2.8 added it with the other predefined conditional types."
      ],
      "examples": [
        "types/nonnullable-basic",
        "types/nonnullable-filter"
      ],
      "sections": [
        {
          "id": "in-helpers",
          "heading": "In generic helpers",
          "body": [
            "A `compact` helper that drops empty values returns `NonNullable<T>[]`. The `filter` callback needs a type predicate, `item is NonNullable<T>`, so that TypeScript accepts the narrowed array as the return value; the second example writes it in a JSDoc comment on the arrow function."
          ]
        }
      ],
      "gotchas": [
        "Without `strict` or `strictNullChecks`, `null` and `undefined` are not tracked and `NonNullable` changes nothing visible.",
        "It removes only `null` and `undefined`; `0`, `\"\"` and `false` stay."
      ],
      "faq": [
        {
          "q": "How do I remove null from a type in JSDoc?",
          "a": "`{NonNullable<YourType>}`, or write the type without `null` if you control it."
        }
      ],
      "related": [
        "types/null-and-undefined",
        "types/exclude-and-extract",
        "types/type-predicates",
        "types/conditional-types"
      ],
      "sources": [
        {
          "title": "Utility Types: NonNullable<Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 2.8: predefined conditional types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "returntype",
      "slug": "returntype",
      "title": "ReturnType<T>",
      "category": "Utility types",
      "jsdoc": "{ReturnType<typeof createCart>}",
      "typescript": "ReturnType<typeof createCart>",
      "since": "2.8",
      "summary": "ReturnType<typeof fn> is the type a function returns. In JSDoc it names a factory's result without writing it twice; .js files also accept it without typeof.",
      "intro": [
        "`ReturnType<typeof createCart>` is the type `createCart()` returns. When a factory function defines an object's shape, this names that shape for other functions' `@param` tags without repeating it, as `Cart` in the first example.",
        "`ReturnType` takes a function type, so the usual spelling puts `typeof` in front of the function's name. TypeScript added it in version 2.8."
      ],
      "examples": [
        "types/returntype-cart",
        "types/returntype-value-name"
      ],
      "sections": [
        {
          "id": "without-typeof",
          "heading": "Without typeof in a .js file",
          "body": [
            "In a `.js` file TypeScript resolves a value's name in a JSDoc type to the value's type, so `ReturnType<createCart>` works there too. The same line in a `.ts` file is TS2749 (\"'createCart' refers to a value, but is being used as a type here. Did you mean 'typeof createCart'?\"); the second example shows both tabs. Write `typeof` so the type means the same in both kinds of file."
          ]
        },
        {
          "id": "async-functions",
          "heading": "Async functions",
          "body": [
            "For an `async` function, `ReturnType` is the `Promise`. Wrap it in `Awaited` for the resolved value: `Awaited<ReturnType<typeof loadAccount>>`."
          ]
        }
      ],
      "gotchas": [
        "For an overloaded function, `ReturnType` uses the last overload.",
        "The factory's return type must be clear to TypeScript; empty arrays and `null` initial values in the returned object need a `@type` comment or a cast, as in the first example, or TypeScript types them as `never[]` and `null`, and nothing else can be stored in them.",
        "TypeScript 7.0 no longer accepts a value's name as a type: `ReturnType<createCart>` is TS2749 there (the section [Under TypeScript 6.0 and 7.0](#typescript-6-0-and-7-0)), so write `ReturnType<typeof createCart>`."
      ],
      "faq": [
        {
          "q": "How do I get a function's return type in JSDoc?",
          "a": "`{ReturnType<typeof yourFunction>}`. For an async function, `{Awaited<ReturnType<typeof yourFunction>>}`."
        }
      ],
      "related": [
        "types/awaited",
        "types/parameters",
        "types/typeof",
        "tags/returns",
        "typescript/7-0"
      ],
      "sources": [
        {
          "title": "Utility Types: ReturnType<Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 2.8: predefined conditional types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "parameters",
      "slug": "parameters",
      "title": "Parameters<T>",
      "category": "Utility types",
      "jsdoc": "{Parameters<typeof addToCart>}",
      "typescript": "Parameters<typeof addToCart>",
      "syntax": [
        {
          "use": "All parameters, as a tuple",
          "jsdoc": "/** @param {Parameters<typeof addToCart>} args */\nfunction f(...args) {}",
          "typescript": "function f(...args: Parameters<typeof addToCart>) {}"
        },
        {
          "use": "One parameter",
          "jsdoc": "/** @typedef {Parameters<typeof addToCart>[2]} AddOptions */",
          "typescript": "type AddOptions = Parameters<typeof addToCart>[2];"
        }
      ],
      "since": "3.1",
      "summary": "Parameters<typeof fn> is a tuple of a function's parameter types. Use it in JSDoc for wrappers that pass arguments through, or to name one parameter type.",
      "intro": [
        "`Parameters<typeof addToCart>` is the tuple `[sku: string, quantity: number, options?: { giftWrap?: boolean }]`. A wrapper that logs, retries or times a call can take `...args` with that type and pass them on, and every call to the wrapper is checked as if it were a call to `addToCart` (TS2345 for a string quantity, as the example shows).",
        "Indexing the tuple names one parameter's type: `Parameters<typeof addToCart>[2]` is the options object. The handbook gives TypeScript 3.1 as the release that added `Parameters`."
      ],
      "examples": [
        "types/parameters-wrapper"
      ],
      "sections": [
        {
          "id": "rest-parameter-tag",
          "heading": "The @param on a rest parameter",
          "body": [
            "For `function addAndLog(...args)`, the tag is `@param {Parameters<typeof addToCart>} args`, the whole tuple, without the three dots. With a tuple type, TypeScript knows the length and the type of each position, optional ones included."
          ]
        }
      ],
      "gotchas": [
        "For a function from a library, `Parameters<typeof libraryFunction>` follows the library's own types and stays right when it upgrades.",
        "`ConstructorParameters<typeof SomeClass>` is the counterpart for a class's constructor."
      ],
      "faq": [
        {
          "q": "How do I type a wrapper function's arguments in JSDoc?",
          "a": "Give the rest parameter the wrapped function's parameter tuple: `@param {Parameters<typeof original>} args` on `function wrapper(...args)`."
        }
      ],
      "related": [
        "types/returntype",
        "types/rest-parameters",
        "types/tuples",
        "types/other-utility-types"
      ],
      "sources": [
        {
          "title": "Utility Types: Parameters<Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "awaited",
      "slug": "awaited",
      "title": "Awaited<T>",
      "category": "Utility types",
      "jsdoc": "{Awaited<ReturnType<typeof loadAccount>>}",
      "typescript": "Awaited<ReturnType<typeof loadAccount>>",
      "since": "4.5",
      "summary": "Awaited<T> is the value a promise resolves to, unwrapped as await does. In JSDoc, Awaited<ReturnType<typeof fn>> names an async function's result.",
      "intro": [
        "`Awaited<T>` unwraps a promise type the way `await` does: `Awaited<Promise<string>>` is `string`, and nested promises are unwrapped all the way. Its most common use is with `ReturnType` on an async function, `Awaited<ReturnType<typeof loadAccount>>`, which names the resolved value. TypeScript 4.5 added it.",
        "Without `Awaited`, the `ReturnType` of an async function is the `Promise` itself, so reading `account.name` from it is TS2339, as the second example shows."
      ],
      "examples": [
        "types/awaited-load",
        "types/awaited-without"
      ],
      "sections": [
        {
          "id": "where-it-shows-up",
          "heading": "Where it shows up",
          "body": [
            "TypeScript uses `Awaited` itself in the types of `Promise.all`, `Promise.race` and `async` function returns, so it appears in hovers and messages even if you never write it. Values that are not promises pass through unchanged: `Awaited<number>` is `number`."
          ]
        }
      ],
      "gotchas": [
        "Before TypeScript 4.5, the usual workaround was a hand-written conditional type with `infer`; `Awaited` replaces it.",
        "`Awaited` unwraps any object with a `then` method that looks like a promise, not only native promises."
      ],
      "faq": [
        {
          "q": "How do I get the resolved type of an async function in JSDoc?",
          "a": "`{Awaited<ReturnType<typeof yourAsyncFunction>>}`."
        }
      ],
      "related": [
        "types/promise",
        "types/returntype",
        "types/conditional-types",
        "tags/async"
      ],
      "sources": [
        {
          "title": "Utility Types: Awaited<Type>",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 4.5: the Awaited type and Promise improvements",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html",
          "publisher": "TypeScript release notes"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "other-utility-types",
      "slug": "other-utility-types",
      "title": "Other utility types",
      "category": "Utility types",
      "jsdoc": "{InstanceType<typeof Cart>}",
      "typescript": "InstanceType<typeof Cart>",
      "syntax": [
        {
          "use": "The instance of a class",
          "jsdoc": "{InstanceType<typeof Cart>}",
          "typescript": "InstanceType<typeof Cart>"
        },
        {
          "use": "A constructor's parameters",
          "jsdoc": "{ConstructorParameters<typeof Cart>}",
          "typescript": "ConstructorParameters<typeof Cart>"
        },
        {
          "use": "Infer from one argument only",
          "jsdoc": "/** @param {NoInfer<T>} fallback */",
          "typescript": "(fallback: NoInfer<T>)"
        },
        {
          "use": "Change a string's case",
          "jsdoc": "{Uppercase<Kind>}",
          "typescript": "Uppercase<Kind>"
        },
        {
          "use": "A function's this type",
          "jsdoc": "{ThisParameterType<typeof fn>}",
          "typescript": "ThisParameterType<typeof fn>"
        }
      ],
      "since": null,
      "summary": "InstanceType, ConstructorParameters, NoInfer, ThisParameterType, OmitThisParameter and the string case types, written in JSDoc as in TypeScript, with examples.",
      "intro": [
        "Besides the common utility types that have their own pages, TypeScript ships several more. All of them work inside JSDoc braces unchanged; this page covers the rest, with what each is for.",
        "`Record<K, V>` has [its own page](/types/record/) under Collections."
      ],
      "examples": [
        "types/other-instance",
        "types/other-string-case",
        "types/other-noinfer"
      ],
      "sections": [
        {
          "id": "classes",
          "heading": "InstanceType and ConstructorParameters",
          "body": [
            "`InstanceType<typeof Cart>` is the type of `new Cart(…)`, and `ConstructorParameters<typeof Cart>` is the tuple of the constructor's parameter types. They matter when a class arrives as a value, for example in a factory typed with a generic constructor type; for a class you can name, `{Cart}` is already the instance type. The handbook lists `InstanceType` from TypeScript 2.8 and `ConstructorParameters` from 3.1."
          ]
        },
        {
          "id": "noinfer",
          "heading": "NoInfer",
          "body": [
            "`NoInfer<T>` stops TypeScript from using an argument to infer `T`. In the third example, `T` is inferred from `sizes` alone, so the `fallback` must be one of those sizes and `\"XL\"` is TS2345. Without `NoInfer`, the fallback would widen `T` to include `\"XL\"`. The handbook lists it from TypeScript 5.4."
          ]
        },
        {
          "id": "string-case",
          "heading": "Uppercase, Lowercase, Capitalize, Uncapitalize",
          "body": [
            "These change the case of string literal types: `Uppercase<\"tee\" | \"mug\">` is `\"TEE\" | \"MUG\"`, so `\"Tee\"` is rejected (TS2820, with a suggestion), as the second example shows. They are mostly used inside template literal types."
          ]
        },
        {
          "id": "this-types",
          "heading": "ThisParameterType and OmitThisParameter",
          "body": [
            "`ThisParameterType<F>` is the declared `this` type of a function type, and `OmitThisParameter<F>` is the same function type without it, which is what `fn.bind(obj)` returns. The handbook lists both from TypeScript 3.3."
          ]
        }
      ],
      "gotchas": [
        "`ThisType<T>` is a marker for object literals that sets the type of `this` inside their methods; it does nothing on its own and needs `noImplicitThis`.",
        "Utility types are ordinary type declarations in TypeScript's standard library, so they need no import and work in every JSDoc tag that takes a type."
      ],
      "faq": [
        {
          "q": "Can I use every TypeScript utility type in JSDoc?",
          "a": "Yes. They are part of TypeScript's built-in library, and a JSDoc type is TypeScript type syntax, so `Partial`, `Pick`, `NoInfer` and the rest all work inside the braces."
        }
      ],
      "related": [
        "types/record",
        "types/constructor-types",
        "types/template-literal-types",
        "types/this-parameter"
      ],
      "sources": [
        {
          "title": "Utility Types",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Template Literal Types: intrinsic string manipulation types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "import-types",
      "slug": "import-types",
      "title": "import() types",
      "category": "Importing and casting",
      "jsdoc": "{import(\"./models.js\").Product}",
      "typescript": "import(\"./models.js\").Product",
      "syntax": [
        {
          "use": "A type from another module",
          "jsdoc": "/** @param {import(\"./models.js\").Product} product */",
          "typescript": "(product: import(\"./models.js\").Product)"
        },
        {
          "use": "A local alias",
          "jsdoc": "/** @typedef {import(\"./models.js\").Product} Product */",
          "typescript": "import type { Product } from \"./models.js\";"
        },
        {
          "use": "A whole module's exports",
          "jsdoc": "/** @param {typeof import(\"./config.js\")} config */",
          "typescript": "(config: typeof import(\"./config.js\"))"
        }
      ],
      "since": "2.9",
      "summary": "An import type, import(\"./models.js\").Product, uses a type from another module inside JSDoc braces without importing anything at run time. Since TypeScript 2.9.",
      "intro": [
        "`import(\"./models.js\").Product` inside JSDoc braces refers to the type `Product` exported from another module. Nothing is imported when the code runs; TypeScript resolves the path the same way it resolves a real `import`, so the extension and your `moduleResolution` setting apply. TypeScript 2.9 added import types.",
        "Writing the path at every use gets long, so a common pattern is a local alias: `/** @typedef {import(\"./models.js\").Product} Product */` once at the top of the file. Since TypeScript 5.5, the `@import` tag does the same job with ES import syntax."
      ],
      "examples": [
        "types/import-types-inline",
        "types/import-types-alias",
        "types/import-types-wrong-path"
      ],
      "sections": [
        {
          "id": "typeof-import",
          "heading": "typeof import()",
          "body": [
            "`typeof import(\"./config.js\")` is the type of the module's exports object, values included: `config.CURRENCY` is typed from `export const CURRENCY = \"USD\"`. Use it to type a parameter that receives a module, such as a set of settings passed around for testing."
          ]
        },
        {
          "id": "what-can-be-imported",
          "heading": "What can be imported",
          "body": [
            "Any exported type: a `@typedef` or `@callback` from a `.js` module, an `interface` or `type` from a `.ts` or `.d.ts` file, a class (as its instance type), and types from packages, `import(\"express\").Request`, when the package ships types or has an `@types` package installed."
          ]
        }
      ],
      "gotchas": [
        "A wrong path is TS2307 on the JSDoc line, as the third example shows; the type is then unusable everywhere it appears.",
        "In ES modules with `module: nodenext`, the path needs its `.js` extension, as in an `import` statement."
      ],
      "faq": [
        {
          "q": "What is the difference between import() types and @import?",
          "a": "Both bring a type from another module into JSDoc without a run-time import. `import(\"./x.js\").Name` works since TypeScript 2.9, right where the type is used; `@import { Name } from \"./x.js\"` needs TypeScript 5.5 and declares the name once per file."
        }
      ],
      "related": [
        "tags/import",
        "tags/typedef",
        "types/typeof",
        "start/node-esm"
      ],
      "sources": [
        {
          "title": "TypeScript 2.9: import types",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "JSDoc Reference: import types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "type-casts",
      "slug": "type-casts",
      "title": "Type casts",
      "category": "Importing and casting",
      "jsdoc": "/** @type {HTMLInputElement} */ (value)",
      "typescript": "value as HTMLInputElement",
      "syntax": [
        {
          "use": "A cast",
          "jsdoc": "/** @type {HTMLInputElement} */ (document.querySelector(\"#email\"))",
          "typescript": "document.querySelector(\"#email\") as HTMLInputElement"
        },
        {
          "use": "Through unknown",
          "jsdoc": "/** @type {Target} */ (/** @type {unknown} */ (value))",
          "typescript": "value as unknown as Target"
        }
      ],
      "since": "2.5",
      "summary": "A JSDoc cast is /** @type {T} */ (expression), parentheses included: the JavaScript spelling of expression as T. When casts fail, and what they never check.",
      "intro": [
        "A `@type` comment directly before a parenthesized expression changes the expression's type: `/** @type {HTMLInputElement} */ (document.querySelector(\"#email\"))` is the JavaScript spelling of `document.querySelector(\"#email\") as HTMLInputElement`. TypeScript 2.5 added the form.",
        "Both parts are required. Without the parentheses the comment is just a comment, and the value keeps its own type, `Element | null`, as the second example shows with two errors on the next line."
      ],
      "examples": [
        "types/casts-dom",
        "types/casts-no-parens",
        "types/casts-unrelated",
        "types/casts-as-syntax"
      ],
      "sections": [
        {
          "id": "what-a-cast-checks",
          "heading": "What a cast checks",
          "body": [
            "Very little. TypeScript only rejects casts between types that do not overlap at all, such as a `string` to a `number` (TS2352, \"Conversion of type 'string' to type 'number' may be a mistake…\"). Anything plausible passes: a cast to `HTMLInputElement` is accepted even if the selector matches a `<div>`, or nothing.",
            "For data from outside (JSON, form values, `postMessage`), prefer a check that narrows, a type predicate or an assertion function, so a wrong assumption fails at once, with a clear message, instead of somewhere later."
          ]
        },
        {
          "id": "as-is-typescript",
          "heading": "as is TypeScript syntax",
          "body": [
            "`value as Type` is an error in a `.js` file (TS8016, \"Type assertion expressions can only be used in TypeScript files\"), as the last example shows."
          ]
        }
      ],
      "gotchas": [
        "After running a formatter over a file full of casts, check that the parentheses survived; Prettier, for one, keeps them when a type comment is attached.",
        "To cast between unrelated types on purpose, go through `unknown` first, as the TS2352 message suggests."
      ],
      "faq": [
        {
          "q": "How do I cast a type in JavaScript with JSDoc?",
          "a": "Put `/** @type {Type} */` before the expression and wrap the expression in parentheses: `/** @type {Type} */ (expression)`."
        }
      ],
      "related": [
        "tags/type",
        "types/non-null-assertions",
        "types/satisfies",
        "types/any-and-unknown"
      ],
      "sources": [
        {
          "title": "TypeScript 2.5: type assertion/cast syntax in checkJs mode",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-5.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "JSDoc Reference: casts",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Everyday Types: type assertions",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "const-assertions",
      "slug": "const-assertions",
      "title": "const assertions",
      "category": "Importing and casting",
      "jsdoc": "/** @type {const} */ ({ … })",
      "typescript": "{ … } as const",
      "syntax": [
        {
          "use": "An object",
          "jsdoc": "const ROUTES = /** @type {const} */ ({ home: \"/\", cart: \"/cart\" });",
          "typescript": "const ROUTES = { home: \"/\", cart: \"/cart\" } as const;"
        },
        {
          "use": "An array",
          "jsdoc": "const SIZES = /** @type {const} */ ([\"S\", \"M\", \"L\"]);",
          "typescript": "const SIZES = [\"S\", \"M\", \"L\"] as const;"
        }
      ],
      "since": "4.5",
      "summary": "/** @type {const} */ (value) is the JSDoc form of as const, since TypeScript 4.5: literal types kept, properties read-only, arrays turned into read-only tuples.",
      "intro": [
        "A cast to `const`, `/** @type {const} */ (value)`, is the JavaScript spelling of TypeScript's `as const`. TypeScript then keeps every literal as its own type (`\"/cart\"`, not `string`), makes every property `readonly`, and turns array literals into read-only tuples. TypeScript 4.5 added the JSDoc form.",
        "It is the usual way to define a fixed set of values once and derive a type from it: `(typeof ROUTES)[keyof typeof ROUTES]` is the union of the route paths, and a path that is not in the object is TS2345."
      ],
      "examples": [
        "types/const-object",
        "types/const-readonly",
        "types/const-tuple",
        "types/const-as-syntax"
      ],
      "sections": [
        {
          "id": "what-changes",
          "heading": "What changes",
          "body": [
            "Without the assertion, `{ home: \"/\" }` is typed `{ home: string }`, because object properties are mutable. With it, the type is `{ readonly home: \"/\" }`: assigning to `ROUTES.cart` is TS2540, and the literal can be used where a union of literals is expected.",
            "An array becomes a read-only tuple: `[0, 0]` is `readonly [0, 0]`, which fits a `readonly [number, number]` parameter where a plain `number[]` does not (TS2345 in the third example)."
          ]
        },
        {
          "id": "not-a-freeze",
          "heading": "Not a freeze",
          "body": [
            "A `const` assertion changes types only. The object can still be modified at run time by code that ignores the types; wrap it in `Object.freeze` as well if that matters."
          ]
        }
      ],
      "gotchas": [
        "The parentheses are required, as with every JSDoc cast.",
        "`as const` itself is TypeScript syntax: in a `.js` file it is TS8016.",
        "Not to be confused with the `@const` tag, which TypeScript ignores."
      ],
      "faq": [
        {
          "q": "How do I write as const in JavaScript?",
          "a": "`/** @type {const} */ (value)`, with the parentheses. It works since TypeScript 4.5."
        }
      ],
      "related": [
        "tags/const",
        "types/indexed-access",
        "types/literal-types",
        "types/type-casts"
      ],
      "sources": [
        {
          "title": "TypeScript 4.5: const assertions and default type arguments in JSDoc",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "TypeScript 3.4: const assertions",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "JSDoc Reference: casts to const",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "satisfies",
      "slug": "satisfies",
      "title": "Annotate, cast or satisfy",
      "category": "Importing and casting",
      "jsdoc": "/** @satisfies {Settings} */",
      "typescript": "satisfies Settings",
      "syntax": [
        {
          "use": "Annotate: the variable has the type",
          "jsdoc": "/** @type {Settings} */\nconst a = { … };",
          "typescript": "const a: Settings = { … };"
        },
        {
          "use": "Cast: claim the type",
          "jsdoc": "const b = /** @type {Settings} */ ({ … });",
          "typescript": "const b = { … } as Settings;"
        },
        {
          "use": "Satisfy: check, keep the value's type",
          "jsdoc": "/** @satisfies {Settings} */\nconst c = { … };",
          "typescript": "const c = { … } satisfies Settings;"
        }
      ],
      "since": "5.0",
      "summary": "Three ways to attach a type to a value in JSDoc: @type annotates, a cast claims, @satisfies checks and keeps the value's own type. When to use each one.",
      "intro": [
        "There are three ways to connect a value to a type, and they behave differently. `@type {Settings}` on a declaration annotates it: the variable has type `Settings`, and the value is checked against it. A cast, `/** @type {Settings} */ (value)`, claims the type: TypeScript checks only that the two types overlap, so missing properties pass. `@satisfies {Settings}` checks the value like an annotation but leaves the variable with the value's own, narrower type.",
        "The first example puts all three side by side. The cast accepts an object without `pageSize`, and only the satisfied object still knows that `theme` is exactly `\"dark\"`. The `@satisfies` tag needs TypeScript 5.0."
      ],
      "examples": [
        "types/satisfies-three-ways",
        "types/satisfies-operator-js"
      ],
      "sections": [
        {
          "id": "choosing",
          "heading": "Choosing one",
          "body": [
            "Annotate variables that will be reassigned or passed around as the general type, and function parameters. Satisfy fixed values whose details matter later: configuration, lookup tables, route maps. Cast only when you know more than TypeScript can, such as the element behind a selector, and keep the cast next to the code that makes it true."
          ]
        }
      ],
      "gotchas": [
        "The `satisfies` operator is TypeScript syntax and TS8037 in a `.js` file, as the second example shows; use the tag.",
        "`@satisfies` does not widen: if you later need the general type, annotate a second variable with `@type`."
      ],
      "faq": [
        {
          "q": "When should I use @satisfies instead of @type?",
          "a": "When the value is fixed and you want TypeScript to remember its exact keys and literal values while still checking it against the type."
        }
      ],
      "related": [
        "tags/satisfies",
        "tags/type",
        "types/type-casts",
        "types/const-assertions"
      ],
      "sources": [
        {
          "title": "TypeScript 5.0: @satisfies support in JSDoc",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "TypeScript 4.9: the satisfies operator",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html",
          "publisher": "TypeScript release notes"
        },
        {
          "title": "Everyday Types: type assertions",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "non-null-assertions",
      "slug": "non-null-assertions",
      "title": "Non-null assertions in JavaScript",
      "category": "Importing and casting",
      "jsdoc": "if (!total) throw …",
      "typescript": "total!",
      "syntax": [
        {
          "use": "Check and stop",
          "jsdoc": "if (!total) throw new Error(\"#total is missing\");",
          "typescript": "total!"
        },
        {
          "use": "Skip when missing",
          "jsdoc": "document.querySelector(\"#badge\")?.classList.add(\"on\");",
          "typescript": "document.querySelector(\"#badge\")?.classList.add(\"on\");"
        },
        {
          "use": "Assertion function",
          "jsdoc": "assert(count, \"#count is missing\");",
          "typescript": "const count = document.querySelector(\"#count\")!;"
        },
        {
          "use": "Cast",
          "jsdoc": "/** @type {HTMLElement} */ (document.querySelector(\"#note\"))",
          "typescript": "document.querySelector(\"#note\") as HTMLElement"
        }
      ],
      "since": null,
      "summary": "TypeScript's ! operator is an error in a .js file. Four alternatives that work there: a check that throws, optional chaining, an assertion function, or a cast.",
      "intro": [
        "In a `.ts` file, `total!.textContent` tells TypeScript that `total` is not `null` or `undefined`. In a `.js` file the `!` operator is TS8013 (\"Non-null assertions can only be used in TypeScript files\"), and there is no JSDoc tag for it. The handbook also notes that `!` inside a JSDoc type, as in `{!HTMLElement}`, has no meaning.",
        "JavaScript code says the same thing in one of four ways, each shown in the second example: check and throw, skip with `?.`, call an assertion function, or cast."
      ],
      "examples": [
        "types/nonnull-operator",
        "types/nonnull-alternatives"
      ],
      "sections": [
        {
          "id": "which-one",
          "heading": "Which one to use",
          "body": [
            "A check that throws is the most honest: it narrows the type and fails with a clear message at the point where the assumption breaks. An assertion function packages the same check for reuse. Optional chaining fits elements that may legitimately be absent.",
            "A cast is the closest to `!` and checks just as little: if the element is missing, the code fails later with a less helpful error. Keep casts for cases a check cannot express."
          ]
        }
      ],
      "gotchas": [
        "`{!Type}` in JSDoc is read as `Type`; it does not remove `null` from the value assigned to it.",
        "Optional chaining returns `undefined` when the value is missing, so its result may need its own check."
      ],
      "faq": [
        {
          "q": "How do I write a non-null assertion in JSDoc?",
          "a": "There is no JSDoc form. Use a check (`if (!el) throw …`), an assertion function, optional chaining, or a cast to the non-null type."
        }
      ],
      "related": [
        "types/null-and-undefined",
        "types/type-casts",
        "types/assertion-functions",
        "types/closure-syntax"
      ],
      "sources": [
        {
          "title": "Everyday Types: non-null assertion operator",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: unsupported patterns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "closure-syntax",
      "slug": "closure-syntax",
      "title": "Closure-style JSDoc types",
      "category": "Legacy syntax",
      "jsdoc": "{?string}",
      "typescript": "string | null",
      "syntax": [
        {
          "use": "Nullable",
          "jsdoc": "{?string}",
          "typescript": "string | null"
        },
        {
          "use": "Non-nullable (no effect)",
          "jsdoc": "{!string}",
          "typescript": "string"
        },
        {
          "use": "Any type",
          "jsdoc": "{*} or {?}",
          "typescript": "any"
        },
        {
          "use": "Arrays",
          "jsdoc": "{Array.<string>}",
          "typescript": "string[]"
        },
        {
          "use": "Dictionaries",
          "jsdoc": "{Object.<string, number>}",
          "typescript": "{ [x: string]: number }"
        },
        {
          "use": "Functions",
          "jsdoc": "{function(string, number=): boolean}",
          "typescript": "(sku: string, min?: number) => boolean"
        },
        {
          "use": "Constructors",
          "jsdoc": "{function(new: Date, string)}",
          "typescript": "new (value: string) => Date"
        },
        {
          "use": "Optional parameter",
          "jsdoc": "@param {string=} label",
          "typescript": "label?: string"
        },
        {
          "use": "Rest parameter",
          "jsdoc": "@param {...number} prices",
          "typescript": "...prices: number[]"
        }
      ],
      "since": null,
      "summary": "Which Closure Compiler JSDoc types TypeScript still accepts: ?string, !string, *, Array.<T>, Object.<K, V>, function(…) types, string= and ...T.",
      "intro": [
        "Much older JavaScript documents types in the style of Google's Closure Compiler. TypeScript reads most of that syntax in `.js` files, so existing comments keep working: `{?string}` is `string | null`, `{Array.<string>}` is `string[]`, `{function(string): boolean}` is a function type. The table below lists each form with its TypeScript meaning.",
        "Two forms do not mean what they did in Closure. `{!Type}` is read as plain `Type`, so it does not strip `null` (the second example fails with TS2322 under `strict`). And the postfix `=` works for parameters but not for properties inside an object type, where it is a syntax error."
      ],
      "examples": [
        "types/closure-accepted",
        "types/closure-bang",
        "types/closure-lowercase-names"
      ],
      "sections": [
        {
          "id": "legacy-names",
          "heading": "Old type names",
          "body": [
            "TypeScript maps some names from older JSDoc to its own: `String`, `Number`, `Boolean`, `Void`, `Undefined` and `Null` to the lowercase types, `function` to `Function`. The handbook lists `array`, `promise`, `Object` and `object` as well, mapped to `any`-based types, but only while `noImplicitAny` is off. With `strict`, lowercase `array` and `promise` are TS2552 (\"Cannot find name 'array'. Did you mean 'Array'?\"), as the third example shows."
          ]
        },
        {
          "id": "modernizing",
          "heading": "Modernizing old comments",
          "body": [
            "There is no need to rewrite working comments in one pass. Convert them as you touch the code: `?string` to `string | null`, `Array.<T>` to `T[]`, `function(…)` to arrow syntax. TypeScript's own messages print the modern forms, so matching them makes errors easier to read."
          ]
        }
      ],
      "gotchas": [
        "`{?}` and `{*}` both mean `any`, not `unknown`; they turn checking off.",
        "`{?string}` only adds `null`; a value that may be `undefined` needs `{string | undefined}`.",
        "Closure's record type `{{a: number}}` is the same as a TypeScript object type and needs no change.",
        "TypeScript 7.0 drops most of these forms: `{?}`, Closure function types and the postfix `!` are not read there ([TypeScript 7.0](/typescript/7-0/#jsdoc); the section [Under TypeScript 6.0 and 7.0](#typescript-6-0-and-7-0) has what 7.0.2 reports for the examples above). The TypeScript spellings in the table work in every version."
      ],
      "faq": [
        {
          "q": "Does TypeScript support Closure Compiler JSDoc syntax?",
          "a": "Mostly. Nullable `?T`, `*`, `Array.<T>`, `Object.<K, V>`, `function(…)` types and the `=` and `...` parameter forms all work in `.js` files; `!T` is accepted but ignored."
        }
      ],
      "related": [
        "types/null-and-undefined",
        "types/function-types",
        "types/record",
        "types/non-null-assertions",
        "typescript/7-0"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: Closure syntax, legacy names and unsupported patterns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Closure Compiler type annotations (the original syntax)",
          "url": "https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System",
          "publisher": "Closure Compiler on GitHub"
        }
      ],
      "updated": "2026-10-21"
    }
  ]
}
