{
  "diagnostics": [
    {
      "id": "ts2322",
      "slug": "ts2322",
      "code": 2322,
      "title": "TS2322: A value does not match its declared type",
      "message": "Type '{0}' is not assignable to type '{1}'.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2322 means a value has a different type from the one its JSDoc annotation declares. How to read the message in a .js file and fix the value or the type.",
      "intro": [
        "`error TS2322: Type 'string' is not assignable to type 'number'.` is the checker's most common error. It appears when a value is stored somewhere whose type was declared: a variable with `@type`, a property of an object typed with a `@typedef`, or the value a function returns under `@returns`. The first type in the message is the value you wrote; the second is the type the annotation promised.",
        "In a JavaScript project the declared type almost always comes from a JSDoc comment, so the fix is either in the value (convert it, correct it) or in the comment (the type was too narrow). The error never changes what runs: it tells you the code and its documentation disagree."
      ],
      "cause": [
        "A `@type` or `@typedef` says a variable or property holds one type, and the code puts a value of another type there (a string where a number is declared, `null` where `null` is not allowed).",
        "A function's `@returns` tag names a type and a `return` statement hands back something else.",
        "With `strictNullChecks` on (part of `strict`), a value that may be `undefined` or `null` is stored where the type does not include them. The message then names `undefined` or `null` as the type that is not assignable."
      ],
      "examples": [
        "errors/ts2322-property-type",
        "errors/ts2322-return-type"
      ],
      "fixes": [
        {
          "id": "fix-the-value",
          "heading": "Fix or convert the value",
          "body": [
            "When the annotation is right, change the value: write the number as a number, or convert text with `Number(...)` before storing it. A `return` that formats a number for display (`toFixed` returns a string) belongs in a separate function whose `@returns` says `string`."
          ],
          "examples": [
            "errors/ts2322-fixed"
          ]
        },
        {
          "id": "widen-the-type",
          "heading": "Or widen the declared type",
          "body": [
            "When the value is right and the comment is too strict, change the comment: `@type {number | string}` for a value that really can be either, `@returns {string}` when the function's job is to format. A union is honest documentation; it also makes every caller handle both cases."
          ]
        },
        {
          "id": "read-the-chain",
          "heading": "Read the whole message for objects",
          "body": [
            "For objects and arrays the first line names the outer types and the indented lines underneath say which property differs. In the editor the squiggle sits on the property itself, which is usually the line to change."
          ]
        }
      ],
      "sections": [
        {
          "id": "where-reported",
          "heading": "Where the error is reported",
          "body": [
            "For an object literal typed with `@type`, TypeScript reports the property that does not fit, not the whole object. For an assignment it reports the variable on the left. For a `return` it reports the returned expression. The examples show all three."
          ]
        }
      ],
      "gotchas": [
        "A cast (`/** @type {number} */ (value)`) silences the error only when the two types overlap; between unrelated types such as `string` and `number` the cast itself is an error (TS2352). Converting the value is almost always the better fix.",
        "Missing or extra properties have their own messages: [TS2741](/errors/ts2741/) and [TS2739](/errors/ts2739/) for missing ones, [TS2353](/errors/ts2353/) for unknown ones in an object literal.",
        "When the value is a function argument the same mismatch is reported as [TS2345](/errors/ts2345/) instead."
      ],
      "faq": [
        {
          "q": "Why does my .js file get TS2322 when JavaScript allows any value anywhere?",
          "a": "Because the file is type-checked (`checkJs` or `// @ts-check`) and a JSDoc comment declared a type. Without the comment the variable's type is whatever it was first given, and later assignments of another type are reported the same way."
        }
      ],
      "related": [
        "tags/type",
        "tags/returns",
        "tags/typedef",
        "types/union",
        "errors/ts2345",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "Everyday Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2345",
      "slug": "ts2345",
      "code": 2345,
      "title": "TS2345: An argument does not match the parameter's type",
      "message": "Argument of type '{0}' is not assignable to parameter of type '{1}'.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2345 means a call passes an argument of the wrong type. The two usual causes in JavaScript, form text and possibly undefined values, and their fixes.",
      "intro": [
        "`error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.` is reported at a call when an argument does not fit the type the function's `@param` tag declares. It is the call-site twin of [TS2322](/errors/ts2322/): same comparison, reported on the argument.",
        "In JavaScript code two cases account for most of these errors: text from the DOM (an input's `value` is always a string) passed where a number is expected, and an optional property passed on as if it were always set. The second only appears with `strictNullChecks`, which `strict` turns on."
      ],
      "cause": [
        "The function's `@param` tag declares a type and the argument has another one.",
        "The argument may be `undefined` or `null` (an optional property, the result of `find`, a DOM lookup) and the parameter's type does not include it. The message then ends with `Type 'undefined' is not assignable to type 'number'.`"
      ],
      "examples": [
        "errors/ts2345-input-value",
        "errors/ts2345-maybe-undefined"
      ],
      "fixes": [
        {
          "id": "convert",
          "heading": "Convert or check the argument at the call",
          "body": [
            "Turn form text into a number with `Number(field.value)`, or read `field.valueAsNumber` on a number input. For a value that may be missing, check it first; after `if (order.discountCents === undefined) return ...` the checker knows the property is a number on the next line."
          ],
          "examples": [
            "errors/ts2345-fixed"
          ]
        },
        {
          "id": "accept-more",
          "heading": "Or let the function accept more",
          "body": [
            "If the function can handle the other type, say so in its JSDoc: `@param {number | undefined} cents`, or an optional parameter `@param {number} [cents]`. Then handle that case inside the function, where it is written once instead of at every call."
          ]
        }
      ],
      "sections": [
        {
          "id": "callbacks",
          "heading": "Arguments that are functions",
          "body": [
            "When the argument is a callback, the message compares function types and the indented lines say which parameter or return type differs. Fix the callback's `@param` tags, or drop them and let the parameter's type supply them: a function passed directly gets its parameter types from the context."
          ]
        }
      ],
      "gotchas": [
        "An object literal argument with a property the parameter's type does not have is reported as [TS2353](/errors/ts2353/), not TS2345.",
        "If the function has several call signatures (overloads, or a built-in such as `new Date()`), a mismatch is reported as [TS2769](/errors/ts2769/) and lists each signature.",
        "`parseInt(field.value)` also converts text, but an empty field gives `NaN` from `parseInt` and `0` from `Number`; the checker only sees `number` either way."
      ],
      "faq": [
        {
          "q": "The value is a number when the code runs. Why does tsc say string?",
          "a": "The checker goes by declared types, not by values at run time. `HTMLInputElement.value` is declared as `string` in TypeScript's DOM types even for `<input type=\"number\">`; `valueAsNumber` is the property declared as `number`."
        }
      ],
      "related": [
        "tags/param",
        "errors/ts2322",
        "errors/ts18048",
        "types/optional-parameters",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "More on Functions",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Narrowing",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "HTMLInputElement: valueAsNumber property",
          "url": "https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/valueAsNumber",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2353",
      "slug": "ts2353",
      "code": 2353,
      "title": "TS2353: An object literal has a property its type does not know",
      "message": "Object literal may only specify known properties, and '{0}' does not exist in type '{1}'.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2353 is the excess property check: an object literal names a property the target type lacks, usually a typo in an options object. How to fix it in JSDoc.",
      "intro": [
        "`error TS2353: Object literal may only specify known properties, and 'hostName' does not exist in type ...` is reported when you write an object literal straight into a typed place (a typed variable, a parameter, a return value) and one of its properties is not part of the type. The checker treats the extra property as a probable typo.",
        "This check, which the handbook calls excess property checking, only applies to object literals written in place. The same object stored in a variable first and passed later is not checked for extra properties, because other code may legitimately add fields to it."
      ],
      "cause": [
        "A property name in an object literal is misspelled or uses another library's name for the option (`hostName` for `host`).",
        "The type is out of date: the option exists in the code but not in the `@typedef` or `@param` type.",
        "The object deliberately carries extra keys (headers, metadata) and the type does not allow them."
      ],
      "examples": [
        "errors/ts2353-misspelled-option"
      ],
      "fixes": [
        {
          "id": "spell-it",
          "heading": "Use the property name the type declares",
          "body": [
            "Most of the time the fix is the spelling. The editor's completion list inside the object literal shows the names the type accepts."
          ],
          "examples": [
            "errors/ts2353-fixed"
          ]
        },
        {
          "id": "extend-the-type",
          "heading": "Add the property to the type, or allow extra keys",
          "body": [
            "If the property is real, add it to the `@typedef` or the `@param` type. If the object is meant to hold any number of named values, give the type an index signature, as the `withHeaders` function in the fixed example does: `{ port: number, [header: string]: string | number }`."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Passing a variable instead of a literal skips the check, so `const options = { hostName: \"x\" }; listen(options)` reports the missing `port` but not the extra `hostName`. Writing options inline is the safer habit.",
        "A cast such as `/** @type {Options} */ ({ ... })` also skips the excess check, which hides typos the same way."
      ],
      "faq": [
        {
          "q": "Why is an extra property an error at all? JavaScript ignores it.",
          "a": "It is ignored at run time, which is exactly the problem: a misspelled option silently does nothing. Reporting it is the checker's way of catching the typo where it is written."
        }
      ],
      "related": [
        "tags/param",
        "tags/typedef",
        "types/object-shapes",
        "types/record",
        "errors/ts2322"
      ],
      "sources": [
        {
          "title": "Object Types: Excess Property Checks",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html#excess-property-checks",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Object Types: Index Signatures",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2741",
      "slug": "ts2741",
      "code": 2741,
      "title": "TS2741: An object is missing a required property",
      "message": "Property '{0}' is missing in type '{1}' but required in type '{2}'.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2741 means an object lacks one property its type requires. Add the property, or mark it optional in the @typedef with brackets.",
      "intro": [
        "`error TS2741: Property 'price' is missing in type '{ sku: string; name: string; }' but required in type 'Product'.` is reported when an object is used as a type that requires a property the object does not have. When two or more are missing the checker lists them instead, as [TS2739](/errors/ts2739/).",
        "In JSDoc every property of a `@typedef` is required unless you say otherwise, just as in a TypeScript interface. The error points at the variable (or argument) whose object falls short."
      ],
      "cause": [
        "The object really is incomplete: a property was forgotten or not loaded yet.",
        "The property is optional in practice but the `@typedef` declares it as required."
      ],
      "examples": [
        "errors/ts2741-missing-property"
      ],
      "fixes": [
        {
          "id": "add-it",
          "heading": "Give the property a value",
          "body": [
            "If the type is right, complete the object. The quick fix **Add missing properties** in editors that run TypeScript's language service writes the missing names with placeholder values."
          ],
          "examples": [
            "errors/ts2741-fixed"
          ]
        },
        {
          "id": "optional",
          "heading": "Or mark the property optional",
          "body": [
            "Put the property name in brackets in its `@property` tag, `@property {number} [price]`, or add a question mark in an inline type, `{ price?: number }`. Code that reads the property then has to handle `undefined`, which is the point: the type now says the value may be absent."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A property that may be absent and a property that is present but `undefined` are the same thing to the checker unless `exactOptionalPropertyTypes` is on.",
        "For a function argument the same problem is reported as [TS2345](/errors/ts2345/) with the TS2741 text as its second line."
      ],
      "related": [
        "tags/property",
        "tags/typedef",
        "types/object-shapes",
        "types/partial",
        "errors/ts2739",
        "config/exact-optional-property-types"
      ],
      "sources": [
        {
          "title": "Everyday Types: Optional Properties",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#optional-properties",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @typedef, @callback and @param",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#typedef-callback-and-param",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2739",
      "slug": "ts2739",
      "code": 2739,
      "title": "TS2739: An object is missing several required properties",
      "message": "Type '{0}' is missing the following properties from type '{1}': {2}",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 2740,
          "message": "Type '{0}' is missing the following properties from type '{1}': {2}, and {3} more."
        }
      ],
      "summary": "TS2739 lists the required properties an object lacks; TS2740 also counts the rest. Complete the object, use Partial, or cast a test stand-in.",
      "intro": [
        "`error TS2739: Type '{ line1: string; city: string; }' is missing the following properties from type 'Address': postalCode, country` is reported when an object lacks two or more properties its type requires. With one missing property the message is [TS2741](/errors/ts2741/) instead; when more than five are missing it becomes TS2740, which names the first four and counts the others (`and 372 more`).",
        "TS2740 is what you see when a small object stands in for a large built-in type, such as a fake `HTMLInputElement` in a test. The DOM types declare hundreds of properties and the checker expects every one of them."
      ],
      "cause": [
        "The object is incomplete for the type it is given: a draft, a partly loaded record, a form being filled in.",
        "A stand-in object (a test double, a mock event) is typed as the full built-in type it imitates."
      ],
      "examples": [
        "errors/ts2739-missing-properties",
        "errors/ts2739-test-double"
      ],
      "fixes": [
        {
          "id": "complete-or-partial",
          "heading": "Complete the object, or say it is partial",
          "body": [
            "Add the missing properties when the object is meant to be whole. When it is legitimately incomplete for a while, type it as `Partial<Address>`, which makes every property optional, and check the fields before using it as an `Address`."
          ],
          "examples": [
            "errors/ts2739-fixed"
          ]
        },
        {
          "id": "cast-stand-ins",
          "heading": "Cast a stand-in object",
          "body": [
            "For a test double, a JSDoc cast says \"treat this as the full type\": `/** @type {HTMLInputElement} */ ({ valueAsNumber: 3 })`, with the parentheses the cast needs. A cast is accepted when one type could be a subset of the other, so a smaller object passes; it does not check that the code under test only reads the properties you supplied."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`Partial` makes every property optional, including the ones you always set. For finer control, list the optional ones in the `@typedef` with brackets.",
        "A cast between types that do not overlap at all (an object with none of the target's properties) is still an error; the checker then suggests casting through `unknown` first."
      ],
      "related": [
        "errors/ts2741",
        "types/partial",
        "types/type-casts",
        "tags/typedef",
        "tags/property"
      ],
      "sources": [
        {
          "title": "Utility Types: Partial",
          "url": "https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: Casts",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#casts",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2355",
      "slug": "ts2355",
      "code": 2355,
      "title": "TS2355: A function with a return type never returns a value",
      "message": "A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2355 means @returns promises a value and the function body never returns one. Usually a forgotten return; sometimes a @type that sets the return type.",
      "intro": [
        "`error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.` is reported when a function's return type is declared, by `@returns` or by a `@type` tag on the function, and its body contains no `return` statement with a value at all. In a `.js` file the error is reported on the type inside the JSDoc tag.",
        "The usual cause is a function that computes its result and forgets to hand it back. A less obvious one is a `@type` tag that types the whole function, such as a framework's handler type with a non-void return; the [Express handler recipe](/recipes/type-an-express-handler/) shows that case."
      ],
      "cause": [
        "The body does the work but never says `return value` (a `.map`, `.replace` or template string whose result is dropped).",
        "A `@type` on a function expression or arrow function declares a function type whose return type is not `void`, and the body is written as if it returns nothing."
      ],
      "examples": [
        "errors/ts2355-no-return"
      ],
      "fixes": [
        {
          "id": "return-it",
          "heading": "Return the value",
          "body": [
            "Add the `return`. In the example the string methods produce a new string and the function drops it."
          ],
          "examples": [
            "errors/ts2355-fixed"
          ]
        },
        {
          "id": "void",
          "heading": "Or declare that the function returns nothing",
          "body": [
            "If the function is called for its side effect, change the tag to `@returns {void}`, or remove `@returns` and let the checker infer `void`. For a handler typed with `@type`, use `@param` tags or `@satisfies` instead, so the return type comes from the body."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "If some paths return a value and others fall off the end, the error is [TS2366](/errors/ts2366/) instead.",
        "`@returns {Promise<string>}` on an `async` function requires a `return` with a string; an `async` function that only awaits work is `Promise<void>`."
      ],
      "related": [
        "tags/returns",
        "errors/ts2366",
        "types/void-and-never",
        "recipes/type-an-express-handler",
        "config/no-implicit-returns"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "More on Functions: Return type void",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html#return-type-void",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2366",
      "slug": "ts2366",
      "code": 2366,
      "title": "TS2366: A function can reach its end without returning",
      "message": "Function lacks ending return statement and return type does not include 'undefined'.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2366 means a path through a function ends without a return while @returns excludes undefined. Why an if chain over every case still trips it.",
      "intro": [
        "`error TS2366: Function lacks ending return statement and return type does not include 'undefined'.` is reported when a function's declared return type (from `@returns`) does not include `undefined` and the checker can find a way to reach the closing brace without a `return`. Falling off the end returns `undefined` in JavaScript, so the declared type would be wrong on that path.",
        "The surprising case is a chain of `if` statements that covers every value of a union: the checker does not treat an `if` chain as exhaustive, so it still sees a path past the last `if`. A `switch` over the same cases is treated as exhaustive."
      ],
      "cause": [
        "A branch was forgotten: an `else`, a default value, a `throw` for impossible input.",
        "Every case is handled by `if` statements, but the checker does not count an `if` chain as covering the union, so the end of the function is still reachable.",
        "`strictNullChecks` is on (it is part of `strict`); without it `undefined` fits every type and this error is not reported."
      ],
      "examples": [
        "errors/ts2366-if-chain"
      ],
      "fixes": [
        {
          "id": "switch-or-final-return",
          "heading": "Use a switch, or make the last case the final return",
          "body": [
            "A `switch` whose cases cover the whole union lets the checker see that the end is unreachable. In an `if` chain, drop the last condition and return unconditionally, or end with `throw new Error(...)` for values that should never arrive."
          ],
          "examples": [
            "errors/ts2366-fixed"
          ]
        },
        {
          "id": "allow-undefined",
          "heading": "Or include undefined in the return type",
          "body": [
            "If falling through is intended, put it in the type: `@returns {number | undefined}`. Callers then have to handle the missing value."
          ]
        }
      ],
      "sections": [
        {
          "id": "no-implicit-returns",
          "heading": "TS2366 and noImplicitReturns",
          "body": [
            "TS2366 is about the declared return type. The separate option [`noImplicitReturns`](/config/no-implicit-returns/) reports a function where some paths return a value and others do not, even without a `@returns` tag ([TS7030](/errors/ts7030/))."
          ]
        }
      ],
      "gotchas": [
        "In a `.js` file the error is reported on the type in the `@returns` tag, not on the function name.",
        "If no path returns anything at all, the message is [TS2355](/errors/ts2355/) instead."
      ],
      "related": [
        "errors/ts2355",
        "config/no-implicit-returns",
        "config/strict-null-checks",
        "types/discriminated-unions",
        "tags/returns"
      ],
      "sources": [
        {
          "title": "Narrowing: Exhaustiveness checking",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: strictNullChecks",
          "url": "https://www.typescriptlang.org/tsconfig/#strictNullChecks",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2362",
      "slug": "ts2362",
      "code": 2362,
      "title": "TS2362: Arithmetic on something that is not a number",
      "message": "The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 2363,
          "message": "The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type."
        }
      ],
      "summary": "TS2362 and TS2363 mean one side of -, *, / or % is not a number: usually a Date or a form field's text. Convert it with getTime() or Number().",
      "intro": [
        "`error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.` and its twin TS2363 (the right-hand side) are reported for `-`, `*`, `/`, `%` and `**` when an operand is not a number. JavaScript converts the operand silently at run time; the checker asks you to do it on purpose.",
        "The two classic cases in JavaScript are subtracting `Date` objects to measure time (`new Date() - startedAt`), which works at run time through `valueOf`, and multiplying an input's `value`, which is a string. `+` is not on the list: with a string it concatenates, so it has its own message ([TS2365](/errors/ts2365/)) when it cannot apply."
      ],
      "cause": [
        "An operand is a `Date`: the checker does not apply `valueOf` for you.",
        "An operand is a string, often `input.value` or a query parameter.",
        "An operand may be `undefined` or `null` under `strictNullChecks`; that case is reported as [TS18048](/errors/ts18048/) or [TS18047](/errors/ts18047/) instead."
      ],
      "examples": [
        "errors/ts2362-date-math"
      ],
      "fixes": [
        {
          "id": "convert",
          "heading": "Convert the operand to a number",
          "body": [
            "Use `date.getTime()` (or `Date.now()` for the current time) for dates, and `Number(text)` or `input.valueAsNumber` for form values. The result is the same number JavaScript would have used, now visible in the code."
          ],
          "examples": [
            "errors/ts2362-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Unary plus (`+startedAt`) also converts and the checker accepts it, but `getTime()` says what is meant.",
        "`Number(\"\")` is `0` and `Number(\"abc\")` is `NaN`; the checker only sees `number`, so validate input before doing arithmetic with it."
      ],
      "related": [
        "errors/ts2365",
        "errors/ts2345",
        "types/primitives",
        "guides/javascript-runtime-types-vs-annotations"
      ],
      "sources": [
        {
          "title": "Date.prototype.getTime()",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "Everyday Types: The primitives",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#the-primitives-string-number-and-boolean",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2365",
      "slug": "ts2365",
      "code": 2365,
      "title": "TS2365: An operator cannot be used with these types",
      "message": "Operator '{0}' cannot be applied to types '{1}' and '{2}'.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2365 means a comparison or + mixes types the checker will not combine, such as a Date with a number or text with a number. Compare numbers with numbers.",
      "intro": [
        "`error TS2365: Operator '<' cannot be applied to types 'Date' and 'number'.` is reported for `<`, `>`, `<=`, `>=` and `+` when the two operands are types the checker does not allow together. Relational operators accept two numbers, two bigints, two strings, `any`, or two values of related types (two `Date` objects compare without complaint); `+` needs numbers, or a string on one side.",
        "In JavaScript code this usually means a `Date` compared with a timestamp, or text from a form compared with a number. Both work at run time through conversion, and both are easy to get subtly wrong, so the checker asks for the conversion to be written."
      ],
      "cause": [
        "A `Date` is compared with a number (`expiresAt < Date.now()`).",
        "A string is compared with a number (`field.value > 10`).",
        "Objects of unrelated types are compared, or two objects are added; JavaScript would convert them to strings or numbers first."
      ],
      "examples": [
        "errors/ts2365-compare-date"
      ],
      "fixes": [
        {
          "id": "same-kind",
          "heading": "Compare numbers with numbers",
          "body": [
            "Call `getTime()` on dates and convert text with `Number(...)` or `valueAsNumber`. Two `Date` objects can be compared with `<` and `>` without conversion (the checker allows it), but equality with `===` compares the objects, not the times, so `getTime()` is the habit worth keeping."
          ],
          "examples": [
            "errors/ts2365-fixed"
          ]
        }
      ],
      "sections": [
        {
          "id": "type-arguments",
          "heading": "When the operator is a pasted type argument",
          "body": [
            "TypeScript code pasted into a `.js` file can produce TS2365 for no visible operator: `first<string>(items)` is read as two comparisons, `first < string` and `> (items)`. The fix is JSDoc instead of type arguments; see [TS2693](/errors/ts2693/)."
          ]
        }
      ],
      "gotchas": [
        "String comparison is allowed (`\"apple\" < \"banana\"`), and compares by UTF-16 code units, so `\"10\" < \"9\"` is true. Convert before comparing numbers held as text.",
        "For `-`, `*`, `/` and `%` the messages are [TS2362 and TS2363](/errors/ts2362/)."
      ],
      "related": [
        "errors/ts2362",
        "errors/ts2367",
        "errors/ts2693",
        "types/primitives"
      ],
      "sources": [
        {
          "title": "Everyday Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Less than (<)",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2367",
      "slug": "ts2367",
      "code": 2367,
      "title": "TS2367: A comparison that can never be true",
      "message": "This comparison appears to be unintentional because the types '{0}' and '{1}' have no overlap.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2367 means === or !== compares types that share no value, so the result never changes. Usually a misspelled literal or a number compared with a string.",
      "intro": [
        "`error TS2367: This comparison appears to be unintentional because the types '\"pending\" | \"shipped\" | \"cancelled\"' and '\"canceled\"' have no overlap.` is reported for `===`, `!==`, `==` and `!=` when no value could belong to both types. The comparison is then always false (or always true for `!==`), which is almost never what the code means.",
        "With string literal unions from JSDoc, this check catches misspelled states the moment you write them. It also catches loose JavaScript habits such as comparing a number with the string `\"0\"`."
      ],
      "cause": [
        "A string literal is misspelled or spelled differently from the union (`\"canceled\"` against `\"cancelled\"`).",
        "A number is compared with a string (or a string with a number) because the value was read as text somewhere else.",
        "The variable was narrowed earlier in the function, so the remaining type no longer contains the value compared against."
      ],
      "examples": [
        "errors/ts2367-no-overlap"
      ],
      "fixes": [
        {
          "id": "match-the-type",
          "heading": "Compare against a value the type can hold",
          "body": [
            "Fix the literal, or convert one side so both are numbers or both are strings. In the editor, completions inside the quotes of `order.status === \"\"` list the union's members."
          ],
          "examples": [
            "errors/ts2367-fixed"
          ]
        },
        {
          "id": "update-the-union",
          "heading": "Or add the value to the union",
          "body": [
            "If the value really can occur (an API added a new status), add it to the `@typedef` union. Every other comparison and `switch` over the union is then checked against the new member too."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "After an early `return` for one case, comparing with that same case later is reported, because the type has been narrowed. In that case the error points at dead code.",
        "`==` gets the same check; it does not let a number and a numeric string through, even though JavaScript coerces them."
      ],
      "related": [
        "types/literal-types",
        "types/union",
        "types/discriminated-unions",
        "errors/ts2365"
      ],
      "sources": [
        {
          "title": "Everyday Types: Literal Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Narrowing: Equality narrowing",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#equality-narrowing",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2769",
      "slug": "ts2769",
      "code": 2769,
      "title": "TS2769: No overload matches the call",
      "message": "No overload matches this call.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2769 means a function with several signatures was called with arguments none of them accept. How to read the per-overload lines and fix the argument.",
      "intro": [
        "`error TS2769: No overload matches this call.` is reported when a function has more than one call signature and the arguments fit none of them. Built-ins such as `new Date()`, `addEventListener`, `Array.prototype.reduce` and `String.prototype.replace` have several, and so does any function written with `@overload` tags.",
        "The message continues with one block per signature (`Overload 1 of 5 ... gave the following error.`). The blocks usually say the same thing in different words; find the signature you meant to call and read its reason. In the example every overload rejects `undefined`."
      ],
      "cause": [
        "An argument has a type that no signature accepts, often `undefined` from an optional property under `strictNullChecks`.",
        "The number of arguments matches no signature.",
        "A callback's parameter or return type fits none of the signatures, for example a `reduce` callback whose accumulator type does not match the initial value."
      ],
      "examples": [
        "errors/ts2769-date-undefined"
      ],
      "fixes": [
        {
          "id": "narrow-first",
          "heading": "Make the argument fit one signature",
          "body": [
            "Check or convert the argument before the call. Once `order.shippedAt` is known to be a string, the `(value: string | number | Date)` signature of `new Date()` matches."
          ],
          "examples": [
            "errors/ts2769-fixed"
          ]
        },
        {
          "id": "your-overloads",
          "heading": "For your own @overload tags, add the missing signature",
          "body": [
            "If the call is legitimate and the function is yours, add an `@overload` for that combination of arguments, or replace the overloads with one signature that takes a union, which the handbook recommends where it is enough."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The overload names in the message come from TypeScript's library files; `VarDate` in the `Date` example is an old Windows Script Host type you can ignore.",
        "Your own functions with `@overload` tags report the same message; the [@overload page](/tags/overload/) shows how the signatures are written."
      ],
      "related": [
        "tags/overload",
        "errors/ts2345",
        "errors/ts18048",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "More on Functions: Function Overloads",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "More on Functions: Writing Good Overloads",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html#writing-good-overloads",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2554",
      "slug": "ts2554",
      "code": 2554,
      "title": "TS2554: The wrong number of arguments",
      "message": "Expected {0} arguments, but got {1}.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 2555,
          "message": "Expected at least {0} arguments, but got {1}."
        }
      ],
      "summary": "TS2554 and TS2555 mean a call passes too few or too many arguments. In JavaScript, @param tags make parameters required; brackets make one optional.",
      "intro": [
        "`error TS2554: Expected 2 arguments, but got 1.` is reported when a call passes a number of arguments the function does not accept. TS2555 (`Expected at least 1 arguments, but got 0.`) is the same error for a function with a rest parameter.",
        "JavaScript has a twist here. A parameter without a JSDoc type is treated as optional, so calling with fewer arguments is fine; once a function has `@param` tags its parameters are required unless a tag marks them optional. Too many arguments is reported either way."
      ],
      "cause": [
        "An argument was forgotten, or one is passed that the function does not take.",
        "The function's `@param` tags make every parameter required, but some are optional in practice."
      ],
      "examples": [
        "errors/ts2554-argument-count"
      ],
      "fixes": [
        {
          "id": "optional-param",
          "heading": "Mark optional parameters in JSDoc",
          "body": [
            "Write the name in brackets, `@param {string} [currency]`, and give it a default in the code if it needs one (`currency = \"USD\"`). The tag can carry the default too, `[currency=\"USD\"]`, but the checker reads only the brackets; the code's default is what runs."
          ],
          "examples": [
            "errors/ts2554-fixed"
          ]
        },
        {
          "id": "match-the-call",
          "heading": "Or change the call",
          "body": [
            "When the function is right, pass what it expects. For a rest parameter (`@param {...string} parts`), the parameters before it are still required."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A function that reads `arguments` instead of named parameters accepts any number of arguments; the checker infers that from the body.",
        "Spreading an array into a function with fixed parameters is a different error, [TS2556](/errors/ts2556/)."
      ],
      "related": [
        "tags/param",
        "types/optional-parameters",
        "types/rest-parameters",
        "errors/ts2556",
        "errors/ts7006"
      ],
      "sources": [
        {
          "title": "Type Checking JavaScript Files: Function parameters are optional by default",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#function-parameters-are-optional-by-default",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @param and @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2556",
      "slug": "ts2556",
      "code": 2556,
      "title": "TS2556: Spreading an array into fixed parameters",
      "message": "A spread argument must either have a tuple type or be passed to a rest parameter.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2556 means ...array was passed to parameters that need an exact count. Type the array as a tuple, use a const cast, or give the function a rest parameter.",
      "intro": [
        "`error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.` is reported for a call like `centerOn(...office)` when `office` is an ordinary array. The checker knows it is a `number[]`, an array of any length, so it cannot tell whether it supplies the two arguments `centerOn` needs.",
        "In JavaScript an array literal is an array of its element type, not a fixed-length tuple. Saying \"exactly these two numbers\" takes a tuple type in JSDoc, or a `const` cast."
      ],
      "cause": [
        "The spread value's type is an array type (`number[]`) and the function has a fixed list of parameters."
      ],
      "examples": [
        "errors/ts2556-spread-array"
      ],
      "fixes": [
        {
          "id": "tuple",
          "heading": "Give the array a tuple type, or cast it to const",
          "body": [
            "`/** @type {[number, number]} */` before the declaration makes it a pair; `/** @type {const} */ ([41.8781, -87.6298])` makes it a read-only tuple of those exact values. Either one lets the spread fill the parameters."
          ],
          "examples": [
            "errors/ts2556-fixed"
          ]
        },
        {
          "id": "rest-param",
          "heading": "Or give the function a rest parameter",
          "body": [
            "If the function works with any number of values, declare it that way: `@param {...number} values` with `...values` in the code. Arrays then spread into it freely."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Built-ins with rest parameters, such as `Math.max(...values)` and `console.log(...parts)`, accept any spread array; `Math.atan2(...pair)` does not.",
        "A `const` cast makes the tuple `readonly`; passing it to a parameter typed as a mutable array is then an error. That only matters when the function expects an array, not separate arguments."
      ],
      "related": [
        "types/tuples",
        "types/const-assertions",
        "types/rest-parameters",
        "errors/ts2554"
      ],
      "sources": [
        {
          "title": "More on Functions: Rest Arguments",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html#rest-arguments",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: Casts (const)",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#casts",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2488",
      "slug": "ts2488",
      "code": 2488,
      "title": "TS2488: A value that is not iterable",
      "message": "Type '{0}' must have a '[Symbol.iterator]()' method that returns an iterator.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2488 means for...of, array destructuring or spread was used on something that is not iterable, usually a plain object. Loop over Object.entries instead.",
      "intro": [
        "`error TS2488: Type '{ theme: string; language: string; }' must have a '[Symbol.iterator]()' method that returns an iterator.` is reported when `for...of`, array destructuring (`const [a] = value`) or array spread (`[...value]`) is used on a value that cannot be iterated. At run time the same code throws `TypeError: settings is not iterable`.",
        "Plain objects are not iterable in JavaScript, even though `for...in` walks their keys. Arrays, strings, `Map`, `Set` and the results of `Object.entries`, `Object.keys` and `Object.values` are."
      ],
      "cause": [
        "A plain object is used where an iterable is needed, often a settings or lookup object that was an array or a `Map` in an earlier version of the code.",
        "A value that may be `undefined` is destructured, and the message shows `undefined` in the type; a `for...of` over such a value is reported as [TS18048](/errors/ts18048/) instead."
      ],
      "examples": [
        "errors/ts2488-object-loop"
      ],
      "fixes": [
        {
          "id": "entries",
          "heading": "Iterate Object.entries, keys or values",
          "body": [
            "`for (const [key, value] of Object.entries(settings))` gives each pair, typed as `[string, string]` here. If the lookup is consulted and changed often, a `Map` is iterable by itself and keeps insertion order."
          ],
          "examples": [
            "errors/ts2488-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`Object.entries` types keys as `string`, not as the object's property names, because an object may carry more properties than its type lists.",
        "`for (const key in settings)` is allowed on a plain object, but reading `settings[key]` inside it is [TS7053](/errors/ts7053/), because `key` is typed as `string`."
      ],
      "related": [
        "types/map-and-set",
        "types/record",
        "types/tuples",
        "errors/ts7053"
      ],
      "sources": [
        {
          "title": "Iteration protocols",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "Object.entries()",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2561",
      "slug": "ts2561",
      "code": 2561,
      "title": "TS2561: An unknown property in an object literal, with a suggestion",
      "message": "Object literal may only specify known properties, but '{0}' does not exist in type '{1}'. Did you mean to write '{2}'?",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2561 is the excess property check with a spelling hint: an object literal names a property its type lacks, and a close one exists. Use the suggested name.",
      "intro": [
        "`error TS2561: Object literal may only specify known properties, but 'retires' does not exist in type 'FetchOptions'. Did you mean to write 'retries'?` is [TS2353](/errors/ts2353/) with a suggestion: an object literal written straight into a typed place has a property the type does not declare, and a declared property is close enough in spelling for the checker to name it.",
        "In plain JavaScript the misspelled option is simply ignored at run time, so a retry count, a timeout or a flag quietly keeps its default. In options objects and reducer actions, this is one of the most useful errors checked JavaScript reports."
      ],
      "cause": [
        "A typo in an option or property name (`retires` for `retries`, `timout` for `timeout`).",
        "A property renamed in the `@typedef` but not at every call site."
      ],
      "examples": [
        "errors/ts2561-misspelled-option"
      ],
      "fixes": [
        {
          "id": "spell-it",
          "heading": "Use the name the checker suggests",
          "body": [
            "Editors that run TypeScript's language service offer the rename as a quick fix. Check that the suggestion is the property you meant before accepting it."
          ],
          "examples": [
            "errors/ts2561-fixed"
          ]
        },
        {
          "id": "extend-the-type",
          "heading": "Or add the property to the type",
          "body": [
            "If the property is real and the type is out of date, add it to the `@typedef` or the `@param` type, as for [TS2353](/errors/ts2353/)."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Like TS2353, the check applies only to object literals written in place. The same object stored in a variable first is not checked for extra properties, so the typo would pass silently.",
        "With `exactOptionalPropertyTypes` or a cast (`/** @type {FetchOptions} */ ({ … })`), the rules change: a cast skips the excess property check entirely."
      ],
      "related": [
        "errors/ts2353",
        "errors/ts2551",
        "recipes/options-object-with-defaults",
        "types/object-shapes",
        "tags/typedef"
      ],
      "sources": [
        {
          "title": "Object Types: excess property checks",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts2684",
      "slug": "ts2684",
      "code": 2684,
      "title": "TS2684: A function called with the wrong this",
      "message": "The 'this' context of type '{0}' is not assignable to method's 'this' of type '{1}'.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2684 means a function that declares its this (with @this, or as a method) is called with a different one, often a plain call. Call it with the right this.",
      "intro": [
        "`error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'HTMLButtonElement'.` is reported when a function says what `this` must be, through a [`@this`](/tags/this/) tag or a `this` parameter in its type, and a call gives it something else. A plain call, `onSave(event)`, gives `this` the type `void`.",
        "In JavaScript the same mistake surfaces at run time as `TypeError: Cannot set properties of undefined` in strict-mode code, or as a write to the global object in sloppy scripts."
      ],
      "cause": [
        "An event handler or method that uses `this` is called directly instead of by the code that sets `this` (`addEventListener`, `call`, `apply`).",
        "A method is taken off its object (`const save = form.save`) and called on its own."
      ],
      "examples": [
        "errors/ts2684-plain-call"
      ],
      "fixes": [
        {
          "id": "give-it-this",
          "heading": "Call it the way it expects",
          "body": [
            "Pass the function to whatever sets `this` (`addEventListener` sets it to the element), or supply it yourself with `call`, `apply` or `bind`."
          ],
          "examples": [
            "errors/ts2684-fixed"
          ]
        },
        {
          "id": "drop-this",
          "heading": "Or stop relying on this",
          "body": [
            "A handler can read the element from `event.currentTarget` instead, and a method can be bound once in the constructor or written as an arrow function field. Then it can be called any way, and the `@this` tag goes."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Passing a `@this` function to `addEventListener` on an element of another type was not reported in this site's tests: the listener overloads accept it. The check covers direct calls.",
        "`@this` on an arrow function is a different error (TS2730), because arrows take `this` from where they are written."
      ],
      "related": [
        "tags/this",
        "types/this-parameter",
        "recipes/this-in-functions",
        "errors/ts2683",
        "recipes/dom-event-listeners"
      ],
      "sources": [
        {
          "title": "More on Functions: declaring this",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html#declaring-this-in-a-function",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @this",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#this",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts1064",
      "slug": "ts1064",
      "code": 1064,
      "title": "TS1064: An async function whose return type is not a Promise",
      "message": "The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<{0}>'?",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS1064 means an async function is annotated with a return type that is not a Promise, often @returns {string}. Write @returns {Promise<string>}.",
      "intro": [
        "An `async` function always returns a promise, whatever its body returns. So its annotated return type has to be `Promise<…>`: `@returns {string}` on an `async` function is TS1064, and the message suggests the right spelling.",
        "In a `.js` file the error is reported on the type in the [`@returns`](/tags/returns/) tag, so the fix is in the comment, not in the code."
      ],
      "cause": [
        "The `@returns` tag describes the value the function body returns rather than what callers receive.",
        "A function was made `async` later and its JSDoc was not updated."
      ],
      "examples": [
        "errors/ts1064-async-returns"
      ],
      "fixes": [
        {
          "id": "promise",
          "heading": "Wrap the type in Promise",
          "body": [
            "Write `@returns {Promise<string>}`. Callers then `await` a string, which is what the code already did."
          ],
          "examples": [
            "errors/ts1064-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Leaving `@returns` out also works: TypeScript infers `Promise<string>` from the body. Exported functions read better with the tag.",
        "The type must be the global `Promise`; a promise-like class from a library is not accepted as an async function's return type."
      ],
      "related": [
        "tags/returns",
        "types/promise",
        "recipes/async-functions",
        "tags/async"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts2775",
      "slug": "ts2775",
      "code": 2775,
      "title": "TS2775: An assertion function called through an untyped name",
      "message": "Assertions require every name in the call target to be declared with an explicit type annotation.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2775 means an assertion function is called through a name with no declared type, such as a property of an untyped object. Call it directly or type the object.",
      "intro": [
        "An assertion function (`@returns {asserts value is string}`) narrows its argument after the call, but only when TypeScript can see the assertion signature without inferring anything: every name in the call, `check.assertString(…)`, must have a declared type. Otherwise the call is TS2775 and nothing is narrowed.",
        "In JavaScript this comes up more often than in TypeScript, because objects, aliases and factory results are usually untyped: an object literal that collects helpers, `const assert = assertString`, or a function that returns one."
      ],
      "cause": [
        "The assertion function is reached through a variable or object whose type is inferred (`const check = { assertString }`).",
        "An alias of the function (`const ensure = assertString`) without a type."
      ],
      "examples": [
        "errors/ts2775-untyped-call-target"
      ],
      "fixes": [
        {
          "id": "declare",
          "heading": "Call the function by its declared name, or declare the type of what holds it",
          "body": [
            "A function declaration has an explicit signature, so calling `assertString(input)` directly works. To keep the object, give it a type with `@type`; the fixed example uses `typeof assertString` for the property."
          ],
          "examples": [
            "errors/ts2775-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A `const` arrow function with its own JSDoc counts as declared, so `/** @param {unknown} v @returns {asserts v is string} */ const assertString = (v) => …` can be called directly.",
        "After a TS2775 call the argument keeps its old type, so the next line often fails too (TS18046 for an `unknown` value)."
      ],
      "related": [
        "recipes/assertion-functions",
        "types/assertion-functions",
        "types/type-predicates",
        "errors/ts18046"
      ],
      "sources": [
        {
          "title": "TypeScript 3.7: assertion functions",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts7030",
      "slug": "ts7030",
      "code": 7030,
      "title": "TS7030: A path that returns no value, under noImplicitReturns",
      "message": "Not all code paths return a value.",
      "category": "Types do not match",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitReturns",
          "effect": "on"
        }
      ],
      "summary": "TS7030 means a function returns a value on some paths and falls off the end on others, with noImplicitReturns on. Return a value on every path.",
      "intro": [
        "With [`noImplicitReturns`](/config/no-implicit-returns/) on, a function that returns a value somewhere must return one on every path. A path that reaches the end of the function returns `undefined` without saying so, and TS7030 points at it.",
        "In a `.js` file the error lands on the function name, or on the type in its `@returns` tag when the function has one."
      ],
      "cause": [
        "An `if` chain that covers some cases and falls through for the rest.",
        "A `switch` without a `default` that returns, or a loop that returns from inside."
      ],
      "examples": [
        "errors/ts7030-missing-return"
      ],
      "fixes": [
        {
          "id": "return",
          "heading": "Return a value on every path",
          "body": [
            "Add the missing `return`, or a final one. If `undefined` is a real result, write `return undefined;` so the intent is visible."
          ],
          "examples": [
            "errors/ts7030-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A function whose return type includes `void` or `any` is exempt. A `@returns {string | undefined}` tag does not exempt it, which is how the strict level of the jsconfig generator finds these.",
        "For a `switch` over every member of a union, TS7030 is not reported when TypeScript can see that the cases are exhaustive; an `if` chain over the same members still ends reachable (compare [TS2366](/errors/ts2366/))."
      ],
      "related": [
        "config/no-implicit-returns",
        "errors/ts2366",
        "guides/choose-a-strictness-level",
        "tags/returns"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: noImplicitReturns",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitReturns",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts2304",
      "slug": "ts2304",
      "code": 2304,
      "title": "TS2304: A name the checker cannot find",
      "message": "Cannot find name '{0}'.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2304 means a name is used that no file in the program declares: often a global a script tag or bundler adds. Declare it in a .d.ts file the config includes.",
      "intro": [
        "`error TS2304: Cannot find name 'gtag'.` is reported when code uses a name that is not declared anywhere the checker can see: not in the file, not imported, not a global from the libraries the config loads. When a declared name is close in spelling, the checker reports [TS2552](/errors/ts2552/) with a suggestion instead.",
        "In a JavaScript project the name usually exists at run time but comes from outside the code: an analytics or map library loaded with a `<script>` tag, a constant a bundler substitutes (`__APP_VERSION__`), or a global from a runtime whose types are not installed."
      ],
      "cause": [
        "A page script or a bundler provides the global, and nothing tells the checker it exists.",
        "The global belongs to a runtime or library whose types the config does not load. For Node.js names such as `process` and `Buffer` the checker says so with [TS2580](/errors/ts2580/) or [TS2591](/errors/ts2591/), and for `console` and `document` with [TS2584](/errors/ts2584/).",
        "The name is defined in a file that is not part of the program (outside `include`)."
      ],
      "examples": [
        "errors/ts2304-page-globals"
      ],
      "fixes": [
        {
          "id": "declare-globals",
          "heading": "Declare the globals in a .d.ts file",
          "body": [
            "Create a file such as `globals.d.ts` with a `declare` line for each global, typed as precisely as you like, and make sure `include` matches it. A declaration file holds types only, so it adds nothing to your JavaScript at run time."
          ],
          "examples": [
            "errors/ts2304-fixed"
          ]
        },
        {
          "id": "install-types",
          "heading": "Or install the library's types",
          "body": [
            "If the global comes from a library with published types, install them (for example `@types/google.maps`) and, if your config has a `types` list, add the package to it. For a few well-known libraries the checker suggests the package itself: `$` without jQuery's types is reported as TS2581 (TS2592 when the config has a `types` list), and both name `@types/jquery`."
          ]
        }
      ],
      "sections": [
        {
          "id": "jsdoc-alternative",
          "heading": "A JSDoc-only alternative",
          "body": [
            "If you would rather not add a `.d.ts` file, read the global through `globalThis` or `window` with a cast: `const gtag = /** @type {(...args: unknown[]) => void} */ (/** @type {any} */ (window).gtag);`. It works, but it has to be repeated in every file, which is why the declaration file is the usual answer."
          ]
        }
      ],
      "gotchas": [
        "A `.d.ts` file only counts when the program includes it. With `\"include\": [\"src/**/*.js\"]` a `src/globals.d.ts` is not matched; add `\"src/**/*.d.ts\"` or list the file.",
        "With `skipLibCheck` on (the `jsconfig.json` default), mistakes inside your own `.d.ts` files are not reported, so keep the declarations simple."
      ],
      "related": [
        "errors/ts2552",
        "errors/ts2339",
        "errors/ts2584",
        "config/include",
        "config/skip-lib-check",
        "config/types"
      ],
      "sources": [
        {
          "title": "Declaration Reference: Global Variables",
          "url": "https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html#global-variables",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Type Checking JavaScript Files",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2339",
      "slug": "ts2339",
      "code": 2339,
      "title": "TS2339: A property the type does not have",
      "message": "Property '{0}' does not exist on type '{1}'.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2339 means code reads a property its type does not declare: window.dataLayer, a field added later, a typo with no close match. Declare it or type the object.",
      "intro": [
        "`error TS2339: Property 'dataLayer' does not exist on type 'Window & typeof globalThis'.` is reported when code reads or writes a property that the value's type does not declare. When a declared property has a similar name, the checker reports [TS2551](/errors/ts2551/) and suggests it instead.",
        "JavaScript files get one allowance TypeScript files do not: assigning a property to an object literal declared in the same file declares the property, so building an object up line by line works. Reading a property nothing declared still fails, and so does adding one to `window` or to an object whose type comes from a JSDoc annotation."
      ],
      "cause": [
        "A global object (`window`, `document`, `globalThis`) is given a property by a third-party script, and the DOM types do not list it.",
        "The object's type comes from an annotation or an initializer that does not include the property (`config.host` when the object was `{ port: 3000 }`).",
        "The name is a typo that is too far from any declared name for a suggestion. This happens most with short names: `response.josn()` gets TS2339, not a hint for `json`."
      ],
      "examples": [
        "errors/ts2339-window-property"
      ],
      "fixes": [
        {
          "id": "declare",
          "heading": "Declare the property where the type is defined",
          "body": [
            "For `window`, add an `interface Window { ... }` block to a `.d.ts` file the config includes; it merges with the DOM's own `Window`. For your own objects, add the property to the `@typedef` or the inline `@type`, optional if it may be absent."
          ],
          "examples": [
            "errors/ts2339-fixed"
          ]
        },
        {
          "id": "assign-in-js",
          "heading": "Build the object in the same file",
          "body": [
            "In a `.js` file, an object literal is open-ended: `const user = {}; user.name = \"Ada\";` declares `name`. A `@type` annotation on the declaration closes it again."
          ],
          "examples": [
            "errors/ts2339-expando"
          ]
        }
      ],
      "sections": [
        {
          "id": "node-vs-fetch",
          "heading": "Same idea, different API",
          "body": [
            "Code written for one API often meets another's types. `res.statusCode` belongs to Node's `http` response; the `fetch` `Response` has `status` instead. TS2339 on a name you are sure exists usually means the value is a different kind of object than you think: hover over it to see its type."
          ]
        }
      ],
      "gotchas": [
        "A property that exists only on some members of a union is TS2339 until the value is narrowed, for example with `\"items\" in value` or a check on a shared `kind` property.",
        "`globalThis.something` is reported as [TS7017](/errors/ts7017/) instead under `noImplicitAny`, when no file assigns it."
      ],
      "related": [
        "errors/ts2551",
        "errors/ts2304",
        "errors/ts7017",
        "tags/typedef",
        "types/object-shapes",
        "types/discriminated-unions"
      ],
      "sources": [
        {
          "title": "Type Checking JavaScript Files: Object literals are open-ended",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#object-literals-are-open-ended",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Declaration Merging: Merging Interfaces",
          "url": "https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2551",
      "slug": "ts2551",
      "code": 2551,
      "title": "TS2551: A misspelled property, with a suggestion",
      "message": "Property '{0}' does not exist on type '{1}'. Did you mean '{2}'?",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2551 means a property does not exist but one with a similar name does, so the checker suggests it. Accept the quick fix, or declare the property you meant.",
      "intro": [
        "`error TS2551: Property 'lenght' does not exist on type 'string[]'. Did you mean 'length'?` is [TS2339](/errors/ts2339/) with a spelling suggestion: the property is not declared, but a declared one is close enough in spelling that the checker names it.",
        "In plain JavaScript the same typo returns `undefined` at run time, which then surfaces somewhere else; `items.lenght` is a common way to get an empty list rendered as if it were full."
      ],
      "cause": [
        "A typo in a property or method name (`lenght`, `heders`).",
        "A name from another API that is close to the real one (for example a plural for a singular)."
      ],
      "examples": [
        "errors/ts2551-typo"
      ],
      "fixes": [
        {
          "id": "accept",
          "heading": "Use the suggested name",
          "body": [
            "Editors that run TypeScript's language service offer the suggestion as a quick fix (**Change spelling to 'length'**). Check it is the property you meant before accepting it."
          ],
          "examples": [
            "errors/ts2551-fixed"
          ]
        },
        {
          "id": "declare",
          "heading": "Or declare the property",
          "body": [
            "If the property is real and the type is missing it, fix the type as for TS2339: extend the `@typedef`, or add an `interface` declaration for a global object."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Suggestions depend on how far the typo is from a real name. Short names with swapped letters often get none: in the example, `response.josn()` is plain TS2339 while `response.heders` gets the hint.",
        "The suggestion can be wrong when two members are similar; reading the type in a hover is quicker than trusting the hint."
      ],
      "related": [
        "errors/ts2339",
        "errors/ts2552",
        "types/object-shapes"
      ],
      "sources": [
        {
          "title": "Everyday Types: Object Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#object-types",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2552",
      "slug": "ts2552",
      "code": 2552,
      "title": "TS2552: A misspelled name, with a suggestion",
      "message": "Cannot find name '{0}'. Did you mean '{1}'?",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2552 means a variable or function name is not declared but a similar one is. Usually a case or spelling slip: use the suggested name.",
      "intro": [
        "`error TS2552: Cannot find name 'subTotal'. Did you mean 'subtotal'?` is [TS2304](/errors/ts2304/) with a suggestion: nothing called `subTotal` is in scope, and a declared name differs only slightly. Mixed-up capitalization is the most common cause.",
        "At run time the same line throws `ReferenceError: subTotal is not defined`, but only when that line runs, and a line in an error branch may never run in testing."
      ],
      "cause": [
        "The name is misspelled or capitalized differently from its declaration.",
        "The name is declared in another scope (inside a different function or block) and a similar name is visible here."
      ],
      "examples": [
        "errors/ts2552-typo"
      ],
      "fixes": [
        {
          "id": "spell-it",
          "heading": "Use the declared name",
          "body": [
            "Accept the editor's **Change spelling** quick fix or correct the name by hand."
          ],
          "examples": [
            "errors/ts2552-fixed"
          ]
        },
        {
          "id": "global",
          "heading": "If the name is a real global, declare it",
          "body": [
            "When the name you wrote is right and comes from a script tag or the environment, the suggestion is a coincidence; declare the global as shown on the [TS2304 page](/errors/ts2304/)."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Lowercase `array` and `promise` in a JSDoc type are also reported as TS2552 under `strict`, with `Array` and `Promise` suggested; in JSDoc the type names are capitalized."
      ],
      "related": [
        "errors/ts2304",
        "errors/ts2551",
        "types/arrays",
        "types/promise"
      ],
      "sources": [
        {
          "title": "Everyday Types",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2451",
      "slug": "ts2451",
      "code": 2451,
      "title": "TS2451: Two files declare the same top-level name",
      "message": "Cannot redeclare block-scoped variable '{0}'.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [
        {
          "option": "moduleDetection",
          "effect": "depends"
        },
        {
          "option": "module",
          "effect": "depends"
        }
      ],
      "summary": "TS2451 across files means the checker treats your .js files as scripts sharing one global scope. Fix with moduleDetection force, an empty export, or a block.",
      "intro": [
        "`error TS2451: Cannot redeclare block-scoped variable 'API_URL'.` is reported when the same `let`, `const` or `class` name is declared twice in one scope. Inside a single file that is a plain mistake. Reported on two different files, it means the checker treats both files as **scripts**: files without `import` or `export`, whose top-level names are globals shared by every script.",
        "Whether that is a bug depends on how the files run. Classic `<script>` tags without `type=\"module\"` really do share one scope, and the second `const API_URL` throws a `SyntaxError` in the browser. Files that a bundler combines, or that load as modules, each have their own scope, and the checker just needs to be told."
      ],
      "cause": [
        "Two or more `.js` files without `import` or `export` declare the same top-level name, and the config's module settings make them scripts. That happens with `module` set to `preserve`, `esnext` or not set, under the default `moduleDetection: \"auto\"`.",
        "With `module: \"nodenext\"` (or `node16` to `node20`) every `.js` file is a module, so this error does not appear across files."
      ],
      "examples": [
        "errors/ts2451-two-scripts",
        "errors/ts2451-two-scripts#checkout.js"
      ],
      "fixes": [
        {
          "id": "module-detection",
          "heading": "If the files are modules, set moduleDetection to force",
          "body": [
            "Anything a bundler or a modern runtime loads is a module. `\"moduleDetection\": \"force\"` in `jsconfig.json` tells the checker so for every file, and the same two files pass unchanged."
          ],
          "examples": [
            "errors/ts2451-module-detection"
          ]
        },
        {
          "id": "export",
          "heading": "Or mark each file with an empty export",
          "body": [
            "`export {};` at the end of a file makes it a module without exporting anything. Only do this for files that are loaded as modules; adding `export` to a classic script makes the browser reject it."
          ],
          "examples": [
            "errors/ts2451-export"
          ]
        },
        {
          "id": "block",
          "heading": "For real classic scripts, keep the names apart",
          "body": [
            "If the files are plain `<script>` tags, the clash is real. Rename one of the two, or wrap each file's code in a block (or an immediately invoked function) so its `const` and `let` names stay local."
          ],
          "examples": [
            "errors/ts2451-block"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`var` and function declarations in two scripts do not clash with each other the same way (JavaScript allows redeclaring them), so the checker merges them instead; mixing `var` in one file with `let` in another is still TS2451.",
        "The [moduleDetection page](/config/module-detection/) shows the same two files under each setting."
      ],
      "related": [
        "config/module-detection",
        "config/module",
        "start/browser"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: moduleDetection",
          "url": "https://www.typescriptlang.org/tsconfig/#moduleDetection",
          "publisher": "TypeScript"
        },
        {
          "title": "Modules: Theory (scripts and modules)",
          "url": "https://www.typescriptlang.org/docs/handbook/modules/theory.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2693",
      "slug": "ts2693",
      "code": 2693,
      "title": "TS2693: A type used where JavaScript needs a value",
      "message": "'{0}' only refers to a type, but is being used as a value here.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2693 means a name that only exists as a type, such as a @typedef or a pasted type argument, is used in running code. Use a type guard or a JSDoc tag instead.",
      "intro": [
        "`error TS2693: 'Product' only refers to a type, but is being used as a value here.` is reported when code that runs (an expression) uses a name that exists only for the checker. A `@typedef` declares a type and nothing at run time, so `value instanceof Product` has no `Product` to test against.",
        "The same message shows up when TypeScript syntax is pasted into a `.js` file: `new Set<string>()` is read as the comparisons `new Set < string > ()`, and `string` is a type, not a value. The parser also reports `Expression expected.` (TS1109) on the empty parentheses."
      ],
      "cause": [
        "A `@typedef` or `@callback` name, or a type imported with `@import`, is used with `instanceof`, `new`, or as a variable.",
        "Type arguments in angle brackets are written in a `.js` file, where they are not syntax."
      ],
      "examples": [
        "errors/ts2693-typedef-value"
      ],
      "fixes": [
        {
          "id": "type-guard",
          "heading": "Check the shape with a type guard",
          "body": [
            "To test whether a value is a `Product`, check its properties in a function whose `@returns {value is Product}` tells the checker what a `true` result means. If you need `instanceof`, make `Product` a class: a class is both a value and a type."
          ],
          "examples": [
            "errors/ts2693-fixed"
          ]
        },
        {
          "id": "jsdoc-type-arguments",
          "heading": "Put type arguments in a JSDoc tag",
          "body": [
            "Instead of `new Set<string>()`, annotate the variable: `/** @type {Set<string>} */ const ids = new Set();`. For a generic function call, annotate the result or cast the argument, as the [generics page](/types/generics/) shows."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The reverse does not apply in a `.js` file: a value's name used as a type in JSDoc, such as `@type {defaults}`, is read as `typeof defaults` and not reported. Writing `typeof` is still clearer.",
        "With an old `lib`, `Promise` and `Symbol` are reported with a variant of this message that suggests changing `lib` (TS2585); see [TS2583](/errors/ts2583/)."
      ],
      "related": [
        "types/type-predicates",
        "types/generics",
        "tags/typedef",
        "errors/ts2365",
        "errors/ts2583",
        "errors/ts8010"
      ],
      "sources": [
        {
          "title": "Narrowing: Using type predicates",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2694",
      "slug": "ts2694",
      "code": 2694,
      "title": "TS2694: An import() type names something the module does not export",
      "message": "Namespace '{0}' has no exported member '{1}'.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2694 in JavaScript usually comes from an import() type in JSDoc whose name the module does not export: a typo, or a type the package calls something else.",
      "intro": [
        "`error TS2694: Namespace '\"/project/types\"' has no exported member 'Prodcut'.` is reported when a dotted type name, `A.B`, points into a module or namespace that has no `B`. In a JavaScript project that almost always means an `import(\"./types.js\").Name` type in a JSDoc tag, where the name after the dot is not something the module exports.",
        "The namespace in the message is the module, shown by its resolved path (tsc prints the full path; this site's examples live at `/project`). For packages it can be an internal name: Express's types, for instance, appear as `e`."
      ],
      "cause": [
        "The type name after the dot is misspelled.",
        "The module does not export that type: it is declared under another name, or in another file of the package.",
        "With `module` set to `preserve` or `esnext`, a file without `import` or `export` is a script, so its `@typedef` is global rather than an export; that case is reported as TS2306 (`File ... is not a module.`) instead. Under `nodenext` every `.js` file is a module, so its top-level `@typedef` names are always exports."
      ],
      "examples": [
        "errors/ts2694-import-type"
      ],
      "fixes": [
        {
          "id": "right-name",
          "heading": "Use the name the module exports",
          "body": [
            "Fix the spelling, or find the exported name: in the editor, completions after `import(\"./types.js\").` list what the module exports. In a `.js` module every `@typedef` at the top level is exported."
          ],
          "examples": [
            "errors/ts2694-fixed"
          ]
        },
        {
          "id": "import-tag",
          "heading": "Consider @import instead",
          "body": [
            "Since TypeScript 5.5, `/** @import { Product } from \"./types.js\" */` names the type once at the top of the file, and a misspelled name is reported on that line, where it is easier to see. See the [@import page](/tags/import/)."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The error is reported on the JSDoc comment, not on the code under it.",
        "In a project where files without `import` or `export` are scripts, an `export {}` line makes a types-only file a module that `import()` types can point at."
      ],
      "related": [
        "types/import-types",
        "tags/import",
        "tags/typedef",
        "errors/ts2305"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: Import types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#import-types",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 5.5 release notes: the @import tag",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2583",
      "slug": "ts2583",
      "code": 2583,
      "title": "TS2583: Map, Set or Promise is missing because the target is old",
      "message": "Cannot find name '{0}'. Do you need to change your target library? Try changing the 'lib' compiler option to '{1}' or later.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [
        {
          "option": "target",
          "effect": "depends"
        },
        {
          "option": "lib",
          "effect": "depends"
        }
      ],
      "alsoCovers": [
        {
          "code": 2585,
          "message": "'{0}' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the 'lib' compiler option to es2015 or later."
        }
      ],
      "summary": "TS2583 and TS2585 mean Map, Set, Promise or Symbol are missing because the config targets ES5, the 5.9 default when no target is set. Set target.",
      "intro": [
        "`error TS2583: Cannot find name 'Map'. Do you need to change your target library?` and its companion TS2585 (`'Promise' only refers to a type, but is being used as a value here.`) are reported when the libraries the checker loads predate ES2015. Without `Map`, `Set`, `Promise` and `Symbol` as values, everyday code fails.",
        "The cause is nearly always a `jsconfig.json` without `target`. TypeScript 5.9 then assumes `es5` and loads the ES5 library. The message suggests changing `lib`, but `lib` follows `target` by default, so setting `target` is the simpler fix."
      ],
      "cause": [
        "No `target` in the config (the default is `es5` in TypeScript 5.9), and no `module` such as `nodenext` that implies a newer one.",
        "A `lib` list that names an old ECMAScript year."
      ],
      "examples": [
        "errors/ts2583-no-target"
      ],
      "fixes": [
        {
          "id": "target",
          "heading": "Set target to the JavaScript your runtimes support",
          "body": [
            "Add `\"target\": \"es2022\"` (or the year your oldest runtime supports) to `compilerOptions`. The ES libraries up to that year load with it, and the same file passes. Setting `module` to `nodenext` also implies a recent target."
          ],
          "examples": [
            "errors/ts2583-fixed"
          ]
        }
      ],
      "sections": [
        {
          "id": "ts6",
          "heading": "TypeScript 6.0",
          "body": [
            "TypeScript 6.0 changes the default `target` to the newest ECMAScript year and deprecates `es5`, per its release notes; the [target page](/config/target/) has the details. Writing `target` explicitly keeps the config's meaning the same across versions."
          ]
        }
      ],
      "gotchas": [
        "Installing `@types/node` can hide this error, because the Node.js types load a newer library themselves. The code then passes for a reason unrelated to the config.",
        "A newer `lib` than the runtime supports makes the checker accept methods that fail when the code runs; match the year to your oldest browser or Node.js version. Methods that are missing for the same reason are [TS2550](/errors/ts2550/)."
      ],
      "related": [
        "config/target",
        "config/lib",
        "errors/ts2550",
        "errors/ts2584",
        "tools/jsconfig-generator"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: target",
          "url": "https://www.typescriptlang.org/tsconfig/#target",
          "publisher": "TypeScript"
        },
        {
          "title": "TSConfig Reference: lib",
          "url": "https://www.typescriptlang.org/tsconfig/#lib",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2584",
      "slug": "ts2584",
      "code": 2584,
      "title": "TS2584: console is missing because lib leaves out the DOM",
      "message": "Cannot find name '{0}'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [
        {
          "option": "lib",
          "effect": "depends"
        },
        {
          "option": "types",
          "effect": "depends"
        }
      ],
      "summary": "TS2584 means console or document is unknown: lib lists only ECMAScript libraries and no Node.js types are loaded. Add @types/node or the dom library.",
      "intro": [
        "`error TS2584: Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.` is reported for `console` and `document` when the checker has no declaration for them; other browser names, such as `window`, are plain TS2304. `console` is not part of the ECMAScript standard: TypeScript declares it in its DOM library, and the Node.js types declare it for Node.js.",
        "It appears after setting `lib` explicitly, for example `[\"es2022\"]` in a Node.js project, without also loading `@types/node`. The message's suggestion, adding `dom`, is right for browser code and wrong for server code."
      ],
      "cause": [
        "`lib` lists ECMAScript libraries only, which removes the DOM library the default would include.",
        "The project runs on Node.js and `@types/node` is not loaded (not installed, or left out of a `types` list)."
      ],
      "examples": [
        "errors/ts2584-no-dom"
      ],
      "fixes": [
        {
          "id": "node",
          "heading": "Node.js code: load the Node.js types",
          "body": [
            "Install `@types/node` and, if the config has a `types` list, add `\"node\"` to it. `console`, `process` and the rest then come from Node's own declarations, and browser-only names stay errors, which is what you want in server code."
          ],
          "examples": [
            "errors/ts2584-node-types"
          ]
        },
        {
          "id": "dom",
          "heading": "Browser code: add dom to lib",
          "body": [
            "For code that runs in a page, write `\"lib\": [\"es2022\", \"dom\"]`, or remove `lib` so it follows `target` with the DOM included."
          ],
          "examples": [
            "errors/ts2584-dom"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`fetch` and `setTimeout` without the DOM or Node.js types are plain [TS2304](/errors/ts2304/), without the hint.",
        "In a project with both browser and server code, give each folder its own config (one with `dom`, one with Node.js types) rather than loading both everywhere."
      ],
      "related": [
        "config/lib",
        "config/types",
        "errors/ts2580",
        "errors/ts2591",
        "start/node-esm",
        "start/browser"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: lib",
          "url": "https://www.typescriptlang.org/tsconfig/#lib",
          "publisher": "TypeScript"
        },
        {
          "title": "TSConfig Reference: types",
          "url": "https://www.typescriptlang.org/tsconfig/#types",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2550",
      "slug": "ts2550",
      "code": 2550,
      "title": "TS2550: A method newer than the configured library",
      "message": "Property '{0}' does not exist on type '{1}'. Do you need to change your target library? Try changing the 'lib' compiler option to '{2}' or later.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [
        {
          "option": "target",
          "effect": "depends"
        },
        {
          "option": "lib",
          "effect": "depends"
        }
      ],
      "summary": "TS2550 means a built-in method such as .at() or replaceAll() is newer than the target or lib the config names. Raise target if your runtimes support the method.",
      "intro": [
        "`error TS2550: Property 'at' does not exist on type 'string[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2022' or later.` is reported when code calls a built-in method that the checker knows was added in a later ECMAScript year than the libraries it loaded. The message names the year that added it.",
        "It is a version question, not a typo. The checker only knows what your config tells it about the runtime: if `target` (or `lib`) says ES2020, methods from 2021 and 2022 are reported, whether or not your Node.js or browsers have them."
      ],
      "cause": [
        "`target` or `lib` names an older year than the method (`.at()` is ES2022, `replaceAll` ES2021, `Object.entries` ES2017, `includes` ES2016).",
        "No `target` at all, which means `es5` in TypeScript 5.9; then `Map` and `Promise` fail too, see [TS2583](/errors/ts2583/)."
      ],
      "examples": [
        "errors/ts2550-old-target"
      ],
      "fixes": [
        {
          "id": "target",
          "heading": "Raise target when every runtime has the method",
          "body": [
            "Set `target` to the year the message names or later. Before you do, check that every runtime you support has the method; MDN's compatibility tables list browser and Node.js versions."
          ],
          "examples": [
            "errors/ts2550-fixed"
          ]
        },
        {
          "id": "older-code",
          "heading": "Or write it the older way",
          "body": [
            "If you support runtimes without the method, keep the target and use the older equivalent: `tags[tags.length - 1]` for `.at(-1)`, `split(\"-\").join(\" \")` or a global regular expression for `replaceAll`. A polyfill works too, but the checker still needs the newer `lib` to know the method exists."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`lib` set explicitly overrides the libraries `target` would pick, so raising `target` alone does nothing if `lib` names an old year.",
        "The checker never adds polyfills or rewrites the code; `noEmit` projects run the JavaScript exactly as written."
      ],
      "related": [
        "config/target",
        "config/lib",
        "errors/ts2583",
        "tools/jsconfig-generator"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: target",
          "url": "https://www.typescriptlang.org/tsconfig/#target",
          "publisher": "TypeScript"
        },
        {
          "title": "Array.prototype.at()",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2582",
      "slug": "ts2582",
      "code": 2582,
      "title": "TS2582: Test globals without the test runner types",
      "message": "Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [
        {
          "option": "types",
          "effect": "depends"
        }
      ],
      "alsoCovers": [
        {
          "code": 2593,
          "message": "Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha` and then add 'jest' or 'mocha' to the types field in your tsconfig."
        }
      ],
      "summary": "TS2582 means a test file uses describe, it or test and no test runner declares them. Load the runner's global types, or import the functions.",
      "intro": [
        "Test runners such as Jest, Mocha and Vitest (with its globals option) put `describe`, `it` and `test` in the global scope. TypeScript knows these names are usually test globals, so instead of plain [TS2304](/errors/ts2304/) it reports TS2582, suggesting types to install.",
        "With a `types` list in the config that leaves the runner out, the same problem is TS2593, whose message adds the step of naming the package in `types`. Names the checker does not associate with test runners, such as `expect`, stay TS2304."
      ],
      "cause": [
        "The runner's types are not installed, or not loaded: a `types` list (this site's configs use `types: []` or a short list) loads only the packages it names.",
        "The test files are checked by a config meant for application code."
      ],
      "examples": [
        "errors/ts2582-no-test-types",
        "errors/ts2582-types-list"
      ],
      "fixes": [
        {
          "id": "globals",
          "heading": "Name the runner's global types",
          "body": [
            "Add the runner's global declarations to `types`: `\"vitest/globals\"` for Vitest with globals on, `\"jest\"` (with `@types/jest` installed) for Jest, `\"mocha\"` for Mocha. The fixed example uses Vitest, which this site has installed."
          ],
          "examples": [
            "errors/ts2582-fixed"
          ]
        },
        {
          "id": "import",
          "heading": "Or import the functions",
          "body": [
            "Runners that export them let you write `import { describe, it, expect } from \"vitest\";` (or `@jest/globals`), which needs no global types at all. The [recipe for test files](/recipes/test-files/) shows both."
          ]
        }
      ],
      "sections": [
        {
          "id": "about-the-example",
          "heading": "About the examples",
          "body": [
            "The first failing example has no `types` list and points `typeRoots` at its own empty folder, to stand for a project with no test runner types installed; the second has a `types` list that leaves the runner out, which is the TS2593 case."
          ]
        }
      ],
      "gotchas": [
        "A separate config for tests (`jsconfig.test.json` extending the main one, with the runner in `types`) keeps test globals out of application files, so a stray `describe` in `src/` is still caught."
      ],
      "related": [
        "recipes/test-files",
        "config/types",
        "errors/ts2304",
        "errors/ts2580"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: types",
          "url": "https://www.typescriptlang.org/tsconfig/#types",
          "publisher": "TypeScript"
        },
        {
          "title": "Vitest: globals",
          "url": "https://vitest.dev/config/globals",
          "publisher": "Vitest docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts4111",
      "slug": "ts4111",
      "code": 4111,
      "title": "TS4111: Dot access to an index signature",
      "message": "Property '{0}' comes from an index signature, so it must be accessed with ['{0}'].",
      "category": "Unknown names and members",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noPropertyAccessFromIndexSignature",
          "effect": "on"
        }
      ],
      "summary": "TS4111 means a property that only an index signature allows is read with a dot, under noPropertyAccessFromIndexSignature. Use brackets, or declare it.",
      "intro": [
        "An index signature (`{ [name: string]: string }`, or `Record<string, string>`) allows any property name, so `env.HOEM` is as valid as `env.HOME`. [`noPropertyAccessFromIndexSignature`](/config/no-property-access-from-index-signature/) makes the difference visible: properties the type declares by name are read with a dot, and the others must use brackets.",
        "The rule changes nothing at run time. Its point is that bracket access marks a name the checker cannot verify, so a typo in a dotted name is never hidden behind an index signature."
      ],
      "cause": [
        "Reading an environment variable, a header or a dictionary entry with a dot (`env.HOME`) from a type that only has an index signature for it."
      ],
      "examples": [
        "errors/ts4111-dot-access"
      ],
      "fixes": [
        {
          "id": "brackets",
          "heading": "Use bracket access",
          "body": [
            "Write `env[\"HOME\"]`. Names the type declares, such as `mode` in the example, keep their dot."
          ],
          "examples": [
            "errors/ts4111-fixed"
          ]
        },
        {
          "id": "declare",
          "heading": "Or declare the property",
          "body": [
            "If the name is always there, add it to the type (`{ HOME: string, [name: string]: string }`); then the dot is fine and a typo in it is an error."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`process.env` is typed with an index signature in `@types/node`, so `process.env.PORT` is TS4111 under this option; the [environment variables recipe](/recipes/environment-variables/) covers it."
      ],
      "related": [
        "config/no-property-access-from-index-signature",
        "types/record",
        "recipes/environment-variables",
        "errors/ts7053"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: noPropertyAccessFromIndexSignature",
          "url": "https://www.typescriptlang.org/tsconfig/#noPropertyAccessFromIndexSignature",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts2531",
      "slug": "ts2531",
      "code": 2531,
      "title": "TS2531: A lookup that may return null, used without a check",
      "message": "Object is possibly 'null'.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2531 means an expression that may be null, such as document.querySelector(...) or localStorage.getItem(...), is used without a check. Three ways to handle it.",
      "intro": [
        "`error TS2531: Object is possibly 'null'.` is reported when code reads a property or calls a method on an expression whose type includes `null`. In browser code the expression is usually a DOM lookup: `document.querySelector(\"#cart-count\")` returns `Element | null`, because the element might not be on the page.",
        "The message names no variable because the value has none: it is the direct result of a call. Store the same result in a variable and the checker reports [TS18047](/errors/ts18047/), `'badge' is possibly 'null'.`, instead. Both only appear with `strictNullChecks`, which `strict` turns on."
      ],
      "cause": [
        "A function that returns `null` when it finds nothing (`querySelector`, `getElementById`, `localStorage.getItem`, `match` on a string) is used as if it always succeeds.",
        "`strictNullChecks` is on. Without it `null` is allowed everywhere and the same code fails only at run time, with `TypeError: Cannot set properties of null`."
      ],
      "examples": [
        "errors/ts2531-query-selector"
      ],
      "fixes": [
        {
          "id": "check",
          "heading": "Check the value, or read it with ?.",
          "body": [
            "Store the result, test it, and use it inside the check: after `if (badge)` the checker knows `badge` is an element. For reads, optional chaining and a default do it in one line: `localStorage.getItem(\"cart\")?.length ?? 0`. Optional chaining cannot be used on the left of an assignment (`a?.b = 1` is TS2779), so writes need the `if`."
          ],
          "examples": [
            "errors/ts2531-fixed"
          ]
        },
        {
          "id": "cast",
          "heading": "Or cast when the markup guarantees the element",
          "body": [
            "If the element is always in the page's HTML, a cast states that: `/** @type {HTMLElement} */ (document.querySelector(\"main\"))`. It also gives a more specific type than `Element`. If the guarantee ever breaks, the code fails at run time, so prefer the check for anything optional."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The `!` operator from TypeScript (`querySelector(\"main\")!`) is a syntax error in a `.js` file, [TS8013](/errors/ts8013/); the cast above is the JSDoc spelling of the same idea.",
        "`querySelector` with a tag name returns the specific element type (`querySelector(\"form\")` is `HTMLFormElement | null`); with a class or id selector it returns `Element | null`, which lacks properties such as `dataset` until you cast or check with `instanceof HTMLElement`."
      ],
      "related": [
        "errors/ts18047",
        "errors/ts2532",
        "types/non-null-assertions",
        "types/type-casts",
        "config/strict-null-checks",
        "start/browser"
      ],
      "sources": [
        {
          "title": "Everyday Types: the null and undefined section",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#null-and-undefined",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Narrowing: Truthiness narrowing",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#truthiness-narrowing",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Document: querySelector() method",
          "url": "https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts18047",
      "slug": "ts18047",
      "code": 18047,
      "title": "TS18047: A variable that may be null, used without a check",
      "message": "'{0}' is possibly 'null'.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS18047 means a variable whose type includes null is used without a check, typically an element from querySelector. Check it once, early.",
      "intro": [
        "`error TS18047: 'form' is possibly 'null'.` is reported when code uses a variable, parameter or property whose type includes `null` as if it could not be `null`. It is the named form of [TS2531](/errors/ts2531/): same check, with the variable's name in the message.",
        "The usual source in JavaScript is a DOM lookup stored in a variable at the top of a file. Checking it once, right after the lookup, narrows the type for every line after it."
      ],
      "cause": [
        "The variable holds the result of something that can return `null` (`querySelector`, `getItem`, `RegExp.exec`, a function whose `@returns` includes `null`).",
        "`strictNullChecks` (part of `strict`) is on."
      ],
      "examples": [
        "errors/ts18047-form"
      ],
      "fixes": [
        {
          "id": "guard",
          "heading": "Check it once, early",
          "body": [
            "`if (!form) throw new Error(...)` (or `return` inside a function) right after the lookup narrows `form` to `HTMLFormElement` for the rest of the scope. A clear message beats `Cannot read properties of null` when the markup changes."
          ],
          "examples": [
            "errors/ts18047-fixed"
          ]
        },
        {
          "id": "optional-chaining",
          "heading": "Or use ?. where missing is fine",
          "body": [
            "`footer?.classList.add(\"ready\")` does nothing when the element is absent. Use it where doing nothing is the right result."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "For a `const`, the check carries into callbacks such as the `submit` handler; for a `let`, only when nothing assigns the variable after the callback is created (TypeScript 5.4 and later). A `let` that is reassigned later is possibly `null` again inside the callback, because the checker cannot know when the callback runs.",
        "For `undefined` the message is [TS18048](/errors/ts18048/), and for a type that includes both, TS18049."
      ],
      "related": [
        "errors/ts2531",
        "errors/ts18048",
        "config/strict-null-checks",
        "types/null-and-undefined",
        "start/browser"
      ],
      "sources": [
        {
          "title": "Narrowing: Control flow analysis",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#control-flow-analysis",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TypeScript 5.4 release notes (narrowing preserved in closures)",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-4.html",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2532",
      "slug": "ts2532",
      "code": 2532,
      "title": "TS2532: A call that may return undefined, used without a check",
      "message": "Object is possibly 'undefined'.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2532 means a property is read on an expression that may be undefined, most often array.find(...). Handle the missing case, or use ?. with a fallback.",
      "intro": [
        "`error TS2532: Object is possibly 'undefined'.` is reported when code reads a property of an expression whose type includes `undefined`. `Array.prototype.find` is the classic case: it returns `undefined` when nothing matches, so `products.find(...).price` has a path that throws.",
        "Like [TS2531](/errors/ts2531/) for `null`, this is the form without a name. Put the result in a variable and the error becomes [TS18048](/errors/ts18048/). With `noUncheckedIndexedAccess` on, reading an array element by index (`items[0].name`) is reported the same way."
      ],
      "cause": [
        "A call that may return `undefined` (`find`, `Map.prototype.get`, `at`) is used directly.",
        "With `noUncheckedIndexedAccess`, an index read such as `items[0]` or `byId[id]` includes `undefined`.",
        "`strictNullChecks` (part of `strict`) is on."
      ],
      "examples": [
        "errors/ts2532-find"
      ],
      "fixes": [
        {
          "id": "handle",
          "heading": "Decide what happens when it is missing",
          "body": [
            "Keep the result, test it, and either throw (when a missing item is a bug) or return a fallback (when it is expected). `products.find(...)?.price ?? null` does the second in one expression and documents it in the return type."
          ],
          "examples": [
            "errors/ts2532-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`filter(...)[0]` has the same problem without the checker noticing (unless `noUncheckedIndexedAccess` is on), because an index read is typed as the element type. `find` is the honest version.",
        "A cast or the `!` operator would hide the error; in a `.js` file `!` is not even allowed ([TS8013](/errors/ts8013/))."
      ],
      "related": [
        "errors/ts18048",
        "errors/ts2531",
        "config/no-unchecked-indexed-access",
        "config/strict-null-checks",
        "types/null-and-undefined"
      ],
      "sources": [
        {
          "title": "Array.prototype.find()",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "TSConfig Reference: noUncheckedIndexedAccess",
          "url": "https://www.typescriptlang.org/tsconfig/#noUncheckedIndexedAccess",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts18048",
      "slug": "ts18048",
      "code": 18048,
      "title": "TS18048: A variable that may be undefined, used without a check",
      "message": "'{0}' is possibly 'undefined'.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS18048 means a variable or optional parameter that may be undefined is used without a check. Check it, give it a default, or say why it is always set.",
      "intro": [
        "`error TS18048: 'note' is possibly 'undefined'.` is reported when a variable, parameter or property whose type includes `undefined` is used as if it were always set. It is the named form of [TS2532](/errors/ts2532/).",
        "In JSDoc, an optional parameter (`@param {string} [note]`) and an optional property (`{ discount?: number }`) both include `undefined`, which is the point of marking them optional: the code using them has to handle the case where they are left out."
      ],
      "cause": [
        "The variable holds a result that may be `undefined` (`find`, `Map.get`, an optional property).",
        "A parameter is marked optional in its `@param` tag, or has `undefined` in its type, and is used without a default or a check.",
        "`strictNullChecks` (part of `strict`) is on."
      ],
      "examples": [
        "errors/ts18048-optional"
      ],
      "fixes": [
        {
          "id": "check-or-default",
          "heading": "Check it, or give it a default",
          "body": [
            "`if (product === undefined) return 0;` narrows the variable for the lines after it. For a parameter, a default value (`note = \"\"`) removes `undefined` from its type inside the function while callers may still leave it out."
          ],
          "examples": [
            "errors/ts18048-fixed"
          ]
        },
        {
          "id": "required",
          "heading": "Or make it required",
          "body": [
            "If every caller passes the value, the brackets in `@param {string} [note]` are wrong: remove them, and calls that leave the argument out are reported instead."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Truthiness checks (`if (note)`) also skip the empty string and `0`. Compare with `undefined` when those values are valid.",
        "`exactOptionalPropertyTypes` changes how optional properties treat an explicit `undefined`, not whether they need a check."
      ],
      "related": [
        "errors/ts2532",
        "errors/ts2345",
        "tags/param",
        "types/optional-parameters",
        "config/strict-null-checks",
        "config/exact-optional-property-types"
      ],
      "sources": [
        {
          "title": "Everyday Types: the null and undefined section",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#null-and-undefined",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @param and @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2722",
      "slug": "ts2722",
      "code": 2722,
      "title": "TS2722: Calling an optional function without a check",
      "message": "Cannot invoke an object which is possibly 'undefined'.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2722 means an optional callback or method is called without checking it exists. Call it with ?.() or give it a no-op default.",
      "intro": [
        "`error TS2722: Cannot invoke an object which is possibly 'undefined'.` is reported when code calls something whose type is a function or `undefined`: an optional callback in an options object, an optional method, a function looked up in a map.",
        "In JavaScript APIs this is the `onProgress` or `onError` option that callers usually leave out. The type says it is optional, so calling it without a check would throw `TypeError: options.onProgress is not a function` for every caller who left it out."
      ],
      "cause": [
        "A property declared with `?` (or a parameter marked optional) holds a function, and the code calls it directly.",
        "`strictNullChecks` (part of `strict`) is on."
      ],
      "examples": [
        "errors/ts2722-optional-callback"
      ],
      "fixes": [
        {
          "id": "optional-call",
          "heading": "Call it with ?.()",
          "body": [
            "`options.onProgress?.(0)` calls the function when it is there and does nothing otherwise. Destructuring with a default, `{ onProgress = () => {} } = {}`, does the same once for the whole function."
          ],
          "examples": [
            "errors/ts2722-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Destructuring without a default (`const { onProgress } = options`) does not change anything: calling `onProgress(0)` is TS2722 too.",
        "If the function is required in practice, remove the `?` from its property; callers that leave it out are then reported where they are written."
      ],
      "related": [
        "errors/ts18048",
        "types/function-types",
        "types/optional-parameters",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "Optional chaining (?.)",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "TSConfig Reference: strictNullChecks",
          "url": "https://www.typescriptlang.org/tsconfig/#strictNullChecks",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2538",
      "slug": "ts2538",
      "code": 2538,
      "title": "TS2538: undefined used as an object key",
      "message": "Type '{0}' cannot be used as an index type.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2538 means a value used as an object key in brackets may be undefined (or is another type that cannot be a key). Pick a fallback key or check first.",
      "intro": [
        "`error TS2538: Type 'undefined' cannot be used as an index type.` is reported for `object[key]` when the key's type includes something that cannot be a property key. In JavaScript projects that something is nearly always `undefined`, from an optional property used as the key.",
        "At run time the code would quietly use the key `\"undefined\"`: `totals[\"undefined\"]` collects every item without a category. The checker reports it instead."
      ],
      "cause": [
        "The key comes from an optional property or parameter (`item.category` where `category?: string`).",
        "The key's type is an object or another type that is not `string`, `number` or `symbol`."
      ],
      "examples": [
        "errors/ts2538-optional-key"
      ],
      "fixes": [
        {
          "id": "fallback-key",
          "heading": "Choose a fallback key, or skip the item",
          "body": [
            "`const key = item.category ?? \"other\"` gives every item a real key; `if (!item.category) continue;` leaves uncategorized items out. Either way the decision is in the code instead of in an accidental `\"undefined\"` entry."
          ],
          "examples": [
            "errors/ts2538-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Without `noUncheckedIndexedAccess`, reading `totals[key]` from a `Record<string, number>` is typed `number` even for a key that was never set, which is why the example writes `?? 0` itself.",
        "Under `noImplicitAny`, a `string` key on an object without an index signature is [TS7053](/errors/ts7053/), a different error."
      ],
      "related": [
        "errors/ts7053",
        "errors/ts18048",
        "types/record",
        "types/indexed-access",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "Object Types: Index Signatures",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Property accessors",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts18046",
      "slug": "ts18046",
      "code": 18046,
      "title": "TS18046: A value of type unknown is used without a check",
      "message": "'{0}' is of type 'unknown'.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "useUnknownInCatchVariables",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "alsoCovers": [
        {
          "code": 2571,
          "message": "Object is of type 'unknown'."
        }
      ],
      "summary": "TS18046 means a variable typed unknown, most often the error in a catch clause, is used before it is narrowed. Check it with instanceof or typeof first.",
      "intro": [
        "`error TS18046: 'err' is of type 'unknown'.` is reported when code reads a property of, or calls, a value typed `unknown` without narrowing it first. The everyday source is `catch (err)`: under `strict`, `useUnknownInCatchVariables` types the caught value as `unknown`, because JavaScript can `throw` anything, not only `Error` objects.",
        "The same check on an expression without a name, such as the result of a function whose `@returns` is `unknown`, is TS2571 (`Object is of type 'unknown'.`). Both say the same thing: prove what the value is before using it."
      ],
      "cause": [
        "`useUnknownInCatchVariables` is on (part of `strict`), so `catch (err)` gives `err` the type `unknown`, and the code reads `err.message`.",
        "A function returns `unknown` (a JSON reader, a message handler), and its result is used directly; that is TS2571 when the result is not stored in a variable."
      ],
      "examples": [
        "errors/ts18046-catch"
      ],
      "fixes": [
        {
          "id": "narrow",
          "heading": "Narrow the value first",
          "body": [
            "For errors, `err instanceof Error ? err.message : String(err)` covers both an `Error` and anything else that was thrown. For data, check the shape with `typeof`, `in` and `!== null`, or write a type guard function once and reuse it."
          ],
          "examples": [
            "errors/ts18046-fixed"
          ]
        },
        {
          "id": "relax",
          "heading": "Or annotate the catch clause, if you accept the risk",
          "body": [
            "`useUnknownInCatchVariables: false` restores the older `any` for catch variables across the project, and `catch (/** @type {any} */ err)` does it for one clause. Both trade the check for convenience; the `instanceof` line is short enough to prefer."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`instanceof Error` is false for errors from another realm (an iframe) and for libraries that throw plain objects; the `String(err)` fallback still prints something.",
        "`unknown` is the type-safe counterpart of `any`: assigning anything to it is allowed, using it is not. The [any and unknown page](/types/any-and-unknown/) compares them."
      ],
      "related": [
        "config/use-unknown-in-catch-variables",
        "types/any-and-unknown",
        "types/type-predicates",
        "config/strict"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: useUnknownInCatchVariables",
          "url": "https://www.typescriptlang.org/tsconfig/#useUnknownInCatchVariables",
          "publisher": "TypeScript"
        },
        {
          "title": "More on Functions: unknown",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html#unknown",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2454",
      "slug": "ts2454",
      "code": 2454,
      "title": "TS2454: A variable is read before it is set",
      "message": "Variable '{0}' is used before being assigned.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictNullChecks",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2454 means a typed variable is read on a path where no value was assigned to it. Give it a starting value, or assign it on every branch.",
      "intro": [
        "`error TS2454: Variable 'discount' is used before being assigned.` is reported when a variable declared with a type but no initial value is read on a path where nothing has assigned it yet. JavaScript would read `undefined`, which the declared type does not allow.",
        "In a `.js` file the error needs a type on the variable (`/** @type {number} */ let discount;`). Without one, the variable's type grows to include `undefined` and the same read is reported as [TS18048](/errors/ts18048/) instead."
      ],
      "cause": [
        "The variable is assigned in some branches (`if (member) discount = 0.1;`) but not all, and read after them.",
        "`strictNullChecks` (part of `strict`) is on."
      ],
      "examples": [
        "errors/ts2454-maybe-unset"
      ],
      "fixes": [
        {
          "id": "initialize",
          "heading": "Start with a value, or assign on every branch",
          "body": [
            "`let discount = 0;` covers the missing branch and lets the checker infer `number`, so the `@type` tag is no longer needed. When the value is chosen by a condition, a `const` with a conditional expression is shorter still."
          ],
          "examples": [
            "errors/ts2454-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A variable assigned inside a callback (`items.forEach(() => { total = ... })`) is not counted as assigned when the code after the call runs, because the checker cannot know the callback ran.",
        "Using a `let` or `const` before its declaration line is a different error (TS2448, used before its declaration); JavaScript throws a `ReferenceError` for it at run time too."
      ],
      "related": [
        "errors/ts18048",
        "tags/type",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "Narrowing: Control flow analysis",
          "url": "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#control-flow-analysis",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: strictNullChecks",
          "url": "https://www.typescriptlang.org/tsconfig/#strictNullChecks",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2375",
      "slug": "ts2375",
      "code": 2375,
      "title": "TS2375: undefined in an optional property, under exactOptionalPropertyTypes",
      "message": "Type '{0}' is not assignable to type '{1}' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.",
      "category": "Null, undefined and unknown",
      "tsCategory": "error",
      "flags": [
        {
          "option": "exactOptionalPropertyTypes",
          "effect": "on"
        }
      ],
      "alsoCovers": [
        {
          "code": 2379,
          "message": "Argument of type '{0}' is not assignable to parameter of type '{1}' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties."
        },
        {
          "code": 2412,
          "message": "Type '{0}' is not assignable to type '{1}' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target."
        }
      ],
      "summary": "TS2375 means an optional property is set to undefined while exactOptionalPropertyTypes is on. Leave the property out, or add undefined to its type.",
      "intro": [
        "With [`exactOptionalPropertyTypes`](/config/exact-optional-property-types/) on, an optional property (`nickname?: string`) may be missing, but it may not be present with the value `undefined`. TS2375 reports an object that has it anyway, in a typed variable; TS2379 reports the same in an argument, and TS2412 in an assignment to the property.",
        "The difference matters to code that checks `\"nickname\" in profile` or iterates over keys: a property set to `undefined` is there, a missing one is not. Without the option, TypeScript treats the two as the same."
      ],
      "cause": [
        "An object literal copies a value that may be `undefined` into an optional property (`{ name, nickname }`).",
        "Code clears an optional property by assigning `undefined` instead of deleting it."
      ],
      "examples": [
        "errors/ts2375-optional-value"
      ],
      "fixes": [
        {
          "id": "leave-it-out",
          "heading": "Leave the property out when there is no value",
          "body": [
            "Build the object without the property when the value is missing, and remove a property with `delete` rather than assigning `undefined`."
          ],
          "examples": [
            "errors/ts2375-leave-out"
          ]
        },
        {
          "id": "allow-undefined",
          "heading": "Or allow undefined in the type",
          "body": [
            "When `undefined` is a meaningful value for the property, say so: `nickname?: string | undefined`. Then both forms are accepted, as without the option."
          ],
          "examples": [
            "errors/ts2375-allow-undefined"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`exactOptionalPropertyTypes` needs `strictNullChecks` (part of `strict`), and it is not part of `strict` itself; the strict level of the [jsconfig generator](/tools/jsconfig-generator/) turns it on.",
        "Library types that declare optional properties without `| undefined` reject an `undefined` value under this option, so passing a library an options object built from values that may be missing is a common source of TS2379."
      ],
      "related": [
        "config/exact-optional-property-types",
        "types/optional-parameters",
        "types/partial",
        "guides/choose-a-strictness-level",
        "config/strict-null-checks"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: exactOptionalPropertyTypes",
          "url": "https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts7006",
      "slug": "ts7006",
      "code": 7006,
      "title": "TS7006: Parameter implicitly has an 'any' type",
      "message": "Parameter '{0}' implicitly has an '{1}' type.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS7006 means a parameter has no type and TypeScript cannot infer one. Why it shows up in checked JavaScript under strict, and the ways to fix it.",
      "intro": [
        "`error TS7006: Parameter 'name' implicitly has an 'any' type.` appears when a function parameter has no type annotation, no default value and no type from its context, and `noImplicitAny` is on. `strict: true` turns `noImplicitAny` on, so this is usually the first error a JavaScript project meets after enabling strict mode.",
        "TypeScript does not work out a parameter's type from the places the function is called. Without a type the parameter is `any`, which switches checking off for everything it touches; `noImplicitAny` turns that silent `any` into an error."
      ],
      "cause": [
        "The parameter has no `@param` tag, no default value, and the function is not passed straight to something that supplies its type (a callback to `map`, an event listener, a typed handler).",
        "`noImplicitAny` is on, either directly or through `strict`."
      ],
      "examples": [
        "errors/ts7006-untyped-param"
      ],
      "fixes": [
        {
          "id": "param-tag",
          "heading": "Give the parameter a type with @param",
          "body": [
            "Add a JSDoc comment above the function with one `@param {Type} name` line per parameter. This is the fix in almost every case, and it documents the function for editors and readers at the same time."
          ],
          "examples": [
            "errors/ts7006-fixed"
          ]
        },
        {
          "id": "default-value",
          "heading": "Give it a default value",
          "body": [
            "A default value carries a type: `function farewell(name = \"friend\")` makes `name` a `string`. Use it when the parameter is optional anyway."
          ]
        },
        {
          "id": "context",
          "heading": "Let the context supply the type",
          "body": [
            "A function passed directly to something typed takes its parameter types from there: in `[\"Ada\", \"Grace\"].map((name) => greet(name))` the arrow function's `name` is a `string` because the array is. A `@type` or `@satisfies` tag on a function expression works the same way."
          ]
        },
        {
          "id": "relax",
          "heading": "Or relax the check while you migrate",
          "body": [
            "Setting `noImplicitAny: false` (or leaving `strict` off) removes the error everywhere, and the parameters stay `any`. That is a reasonable first step in a large codebase, and it is what the relaxed level of the [jsconfig generator](/tools/jsconfig-generator/) does."
          ]
        }
      ],
      "sections": [
        {
          "id": "js-and-ts",
          "heading": "The same error in .js and .ts files",
          "body": [
            "The error and its fixes are the same in both kinds of file; only the spelling of the annotation differs. In a `.ts` file you write `name: string`, in a `.js` file the type goes in the `@param` tag. The TypeScript tab on the fixed example shows the two side by side."
          ]
        }
      ],
      "gotchas": [
        "A `@param` tag whose name does not match the parameter does not fix the error. The parameter is still untyped (TS7006), and the checker reports the stray tag separately ([TS8024](/errors/ts8024/)).",
        "Destructured parameters get one tag for the whole object: `@param {{ id: string, name: string }} user` above `function show({ id, name })`. The tag's name is yours to choose.",
        "Callbacks are only typed by their context when they are passed directly. A function defined on its own line and passed later needs its own `@param` tags."
      ],
      "faq": [
        {
          "q": "Why doesn't TypeScript infer the type from how I call the function?",
          "a": "Types flow from a function's body and its context to its callers, not back from the call sites. With `noImplicitAny` off, editors offer a quick fix that suggests types from usage (TS7044), but the checker never applies it on its own."
        }
      ],
      "related": [
        "tags/param",
        "tags/type",
        "errors/ts7031",
        "errors/ts7034",
        "config/no-implicit-any",
        "tools/jsconfig-generator"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: noImplicitAny",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitAny",
          "publisher": "TypeScript"
        },
        {
          "title": "TSConfig Reference: strict",
          "url": "https://www.typescriptlang.org/tsconfig/#strict",
          "publisher": "TypeScript"
        },
        {
          "title": "JSDoc Reference: @param and @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7008",
      "slug": "ts7008",
      "code": 7008,
      "title": "TS7008: A class field without a type",
      "message": "Member '{0}' implicitly has an '{1}' type.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS7008 means a class field has no type the checker can use: declared bare, or only ever set to an empty array or null. Add a @type tag above the field.",
      "intro": [
        "`error TS7008: Member 'items' implicitly has an 'any[]' type.` is reported for a class property whose type would fall back to `any` (or `any[]`) under `noImplicitAny`. In a `.js` file the checker types a property from the values assigned to it in the class, so the error means none of those values tells it anything: the field is declared bare (`items;`), or set only to `[]`, `null` or `undefined`.",
        "A field assigned a real value in the constructor is fine without a tag: `owner` in the example gets `string` from `this.owner = owner`. Empty arrays are the common trap, because `[]` says nothing about what will go in it."
      ],
      "cause": [
        "A class field is declared without an initializer and nothing in the class assigns it a typed value.",
        "Every assignment is `[]`, `null` or `undefined`, which in a `.js` file leave the type as `any` or `any[]`.",
        "`noImplicitAny` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts7008-class-field"
      ],
      "fixes": [
        {
          "id": "type-tag",
          "heading": "Put a @type tag on the field",
          "body": [
            "`/** @type {string[]} */` on the line above `items = [];` gives the field its type. For a property created in the constructor, put the tag above the assignment: `/** @type {string[]} */ this.items = [];`. A field initialized with a value the checker can read (`createdAt = new Date()`) needs no tag."
          ],
          "examples": [
            "errors/ts7008-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Properties that are only assigned in a method (not the constructor or the field list) are treated as optional, so code reading them must handle `undefined`.",
        "A `@type` on a field without an initializer is also checked by `strictPropertyInitialization`: if the constructor does not set it, that is [TS2564](/errors/ts2564/)."
      ],
      "related": [
        "tags/type",
        "errors/ts2564",
        "errors/ts7034",
        "config/no-implicit-any",
        "tags/class"
      ],
      "sources": [
        {
          "title": "Type Checking JavaScript Files: Properties are inferred from assignments in class bodies",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#properties-are-inferred-from-assignments-in-class-bodies",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: noImplicitAny",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitAny",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7017",
      "slug": "ts7017",
      "code": 7017,
      "title": "TS7017: Reading a global through globalThis that nothing declares",
      "message": "Element implicitly has an 'any' type because type '{0}' has no index signature.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS7017 in JavaScript is usually globalThis.SOMETHING that no file declares: a flag or config a script tag sets. Declare it with var in a .d.ts file.",
      "intro": [
        "`error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.` is reported when code reads a property from a type that has no such property and no index signature to fall back on. In JavaScript projects the type is nearly always `typeof globalThis`: code reads `globalThis.DEBUG` or `globalThis.APP_CONFIG`, set by a `<script>` tag or a test setup file the checker never sees.",
        "On `window` the same mistake is [TS2339](/errors/ts2339/) instead. Both mean the same thing: the global exists at run time, but no declaration tells the checker about it."
      ],
      "cause": [
        "A global set outside the checked files (inline script, server-rendered config, test setup) is read through `globalThis`.",
        "`noImplicitAny` is on (part of `strict`); without it the read is silently `any`."
      ],
      "examples": [
        "errors/ts7017-global-this"
      ],
      "fixes": [
        {
          "id": "declare-var",
          "heading": "Declare it with var in a .d.ts file",
          "body": [
            "In a declaration file the config includes, write `declare var DEBUG: boolean | undefined;`. It must be `var`: `var` declarations become properties of `globalThis`, `let` and `const` do not. Include `undefined` in the type if pages may leave it out."
          ],
          "examples": [
            "errors/ts7017-fixed"
          ]
        },
        {
          "id": "assign-in-js",
          "heading": "Or set it in a checked file",
          "body": [
            "If one of your own `.js` files sets the global (`globalThis.DEBUG = false;`), that assignment declares it for every other file in the program, and reads elsewhere pass."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`declare const DEBUG: boolean;` makes the bare name `DEBUG` work, but `globalThis.DEBUG` is then TS2339: only `var` declarations are properties of `globalThis`.",
        "Indexing your own objects with a string key is a different message, [TS7053](/errors/ts7053/)."
      ],
      "related": [
        "errors/ts2339",
        "errors/ts2304",
        "errors/ts7053",
        "config/no-implicit-any"
      ],
      "sources": [
        {
          "title": "globalThis",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "Declaration Reference: Global Variables",
          "url": "https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html#global-variables",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7023",
      "slug": "ts7023",
      "code": 7023,
      "title": "TS7023: A recursive function needs a return type",
      "message": "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "alsoCovers": [
        {
          "code": 7022,
          "message": "'{0}' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer."
        }
      ],
      "summary": "TS7023 and TS7022 mean the checker cannot infer a type because it depends on itself: a recursive function, or a variable set from that function. Add @returns.",
      "intro": [
        "`error TS7023: 'depth' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.` is reported for a recursive function whose return type the checker would have to know in order to work it out. To infer `depth`'s return type it needs the type of `depth(node.parent) + 1`, which needs `depth`'s return type.",
        "TS7022 is the same circle through a variable: in the retry example `retried` holds the result of `fetchWithRetry`, whose return type depends on `retried`. One `@returns` tag on the function breaks both."
      ],
      "cause": [
        "A function calls itself in a `return` expression (directly or through another function) and has no `@returns` tag.",
        "A variable is initialized from such a function and then returned from it (TS7022).",
        "`noImplicitAny` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts7023-recursive",
        "errors/ts7023-retry"
      ],
      "fixes": [
        {
          "id": "returns",
          "heading": "Add @returns to the function",
          "body": [
            "With `@returns {number}` (or `@returns {Promise<Response>}` for the async retry), the checker no longer has to infer the return type, and the variable that holds the result takes its type from the tag."
          ],
          "examples": [
            "errors/ts7023-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Some recursive functions pass without the tag. Checked here with TypeScript 5.9, `if (!node.parent) return node; return root(node.parent);` was accepted, while `return n <= 1 ? 1 : n * factorial(n - 1);` was TS7023. The tag is the reliable fix, and it documents the function.",
        "The error is reported on the function name, not on the recursive call."
      ],
      "related": [
        "tags/returns",
        "errors/ts7006",
        "config/no-implicit-any",
        "types/promise"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @param and @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: noImplicitAny",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitAny",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7031",
      "slug": "ts7031",
      "code": 7031,
      "title": "TS7031: A destructured parameter without a type",
      "message": "Binding element '{0}' implicitly has an '{1}' type.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS7031 means a destructured parameter such as { name, email } has no type, so each name is reported. One @param tag for the whole object fixes them all.",
      "intro": [
        "`error TS7031: Binding element 'name' implicitly has an 'any' type.` is the destructuring form of [TS7006](/errors/ts7006/): a parameter written as `{ name, email }` (or `[first, second]`) has no type, so every name pulled out of it is reported once.",
        "JSDoc has no place to put a type next to each name, so the tag describes the whole object. The tag's name is yours to pick, because the parameter itself has none."
      ],
      "cause": [
        "A parameter is a destructuring pattern and there is no `@param` tag for it, no default value with a type, and no context (a typed callback) to supply one.",
        "`noImplicitAny` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts7031-destructured"
      ],
      "fixes": [
        {
          "id": "param-object",
          "heading": "Describe the object in one @param tag",
          "body": [
            "`@param {{ name: string, email: string }} user` types both names. For a longer list, the nested form reads better: `@param {object} options` followed by `@param {string} options.name` and `@param {boolean} [options.compact]`, with brackets for optional ones. A `@typedef` works too, when other functions take the same object."
          ],
          "examples": [
            "errors/ts7031-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A default in the pattern (`compact = false`) types that one name, but the others still need the tag.",
        "The names in nested `@param` tags must match the destructured names. A misspelled one (`options.nam`) describes a property the pattern does not read, so the destructured `name` is reported as [TS2339](/errors/ts2339/)."
      ],
      "related": [
        "errors/ts7006",
        "tags/param",
        "tags/typedef",
        "types/object-shapes",
        "config/no-implicit-any"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @param and @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "More on Functions: Parameter Destructuring",
          "url": "https://www.typescriptlang.org/docs/handbook/2/functions.html#parameter-destructuring",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7034",
      "slug": "ts7034",
      "code": 7034,
      "title": "TS7034: A variable whose type cannot be settled",
      "message": "Variable '{0}' implicitly has type '{1}' in some locations where its type cannot be determined.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "alsoCovers": [
        {
          "code": 7005,
          "message": "Variable '{0}' implicitly has an '{1}' type."
        }
      ],
      "summary": "TS7034 and TS7005 mean a variable started as [], null or nothing and the checker cannot follow its type, often because a closure uses it. Annotate the variable.",
      "intro": [
        "`error TS7034: Variable 'tags' implicitly has type 'any[]' in some locations where its type cannot be determined.` is reported on a declaration such as `let tags = [];` or `let config;`, and TS7005 (`Variable 'tags' implicitly has an 'any[]' type.`) on the places that read it.",
        "The checker can usually follow such a variable: after `tags.push(\"a\")` in the same function it knows `tags` holds strings. It loses track when the variable is captured by another function (a callback, an arrow function) or exported, because it cannot know when that other code runs. Then the variable is `any`, and `noImplicitAny` reports it."
      ],
      "cause": [
        "A variable is declared with `[]`, `null`, `undefined` or no value, and it is used inside a nested function or exported (`export let lastError;` is reported on its own as TS7005).",
        "`noImplicitAny` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts7034-empty-array"
      ],
      "fixes": [
        {
          "id": "annotate",
          "heading": "Annotate the variable",
          "body": [
            "`/** @type {string[]} */` above `let tags = [];`, or `/** @type {Error | undefined} */` above `export let lastError;`. The annotation fixes the declaration and every TS7005 that came from it."
          ],
          "examples": [
            "errors/ts7034-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Without a closure the same `let list = []; list.push(\"a\"); return list;` passes: the checker follows the pushes and types `list` as `string[]`.",
        "An empty array assigned to a class field reports [TS7008](/errors/ts7008/) instead."
      ],
      "related": [
        "tags/type",
        "errors/ts7008",
        "errors/ts7006",
        "config/no-implicit-any",
        "types/arrays"
      ],
      "sources": [
        {
          "title": "Type Checking JavaScript Files: null, undefined, and empty array initializers are of type any or any[]",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#null-undefined-and-empty-array-initializers-are-of-type-any-or-any",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: noImplicitAny",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitAny",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7053",
      "slug": "ts7053",
      "code": 7053,
      "title": "TS7053: Indexing an object with a string key",
      "message": "Element implicitly has an 'any' type because expression of type '{0}' can't be used to index type '{1}'.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS7053 means obj[key] uses a string key on an object whose type lists fixed properties. Type the key as keyof typeof obj, or the object as a Record.",
      "intro": [
        "`error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ tea: number; coffee: number; cocoa: number; }'.` is reported for `object[key]` when `key` is any string and the object's type only has a fixed set of properties. The checker cannot tell which property you get, so the result would be `any`.",
        "It is one of the most common errors in JavaScript code that turns on `strict`: lookup tables indexed by a parameter, `for...in` loops, and `event.target.name` used as a key all produce it."
      ],
      "cause": [
        "The key is typed `string` (a parameter, a `for...in` variable, a form field name) and the object is an object literal or a `@typedef` without an index signature.",
        "`noImplicitAny` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts7053-string-key"
      ],
      "fixes": [
        {
          "id": "keyof",
          "heading": "Narrow the key's type",
          "body": [
            "If only the object's own keys are valid, say so: `@param {keyof typeof prices} drink`. Callers passing an arbitrary string are then reported where it matters. For a string from outside (a URL, a form), check it first with a type guard such as `isDrink` in the example, written with `Object.hasOwn`."
          ],
          "examples": [
            "errors/ts7053-fixed"
          ]
        },
        {
          "id": "record",
          "heading": "Or give the object an index signature",
          "body": [
            "If the object is a dictionary that any key may be looked up in, type it as one: `/** @type {Record<string, number | undefined>} */`. Including `undefined` makes the result honest for missing keys. A `Map` is the other good choice for open-ended keys."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`if (key in prices)` does not narrow `key`, so `prices[key]` inside it is still TS7053; the type guard function is the JSDoc way to narrow it.",
        "A cast on the key, `/** @type {keyof typeof prices} */ (key)`, also silences the error, without any check at run time."
      ],
      "related": [
        "types/keyof",
        "types/typeof",
        "types/record",
        "types/map-and-set",
        "errors/ts2538",
        "config/no-implicit-any"
      ],
      "sources": [
        {
          "title": "Keyof Type Operator",
          "url": "https://www.typescriptlang.org/docs/handbook/2/keyof-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Object Types: Index Signatures",
          "url": "https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2683",
      "slug": "ts2683",
      "code": 2683,
      "title": "TS2683: this has no type in a plain function",
      "message": "'this' implicitly has type 'any' because it does not have a type annotation.",
      "category": "Implicit any",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitThis",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2683 means a function that is not a method uses this, so the checker does not know what this is. Declare it with @this, or use event.currentTarget.",
      "intro": [
        "`error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.` is reported when `this` is used in a function that is not a method of a class or an object literal, so the checker has no way to know what it will be. With `noImplicitThis` on (part of `strict`), that `any` is an error.",
        "In browser JavaScript the typical case is a named function used as an event handler: `addEventListener` calls it with `this` set to the element. The checker does not read that from the later `addEventListener` call, because the function is declared on its own."
      ],
      "cause": [
        "A function declaration or expression uses `this` and is not part of a class or object literal.",
        "`noImplicitThis` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts2683-this"
      ],
      "fixes": [
        {
          "id": "this-tag",
          "heading": "Declare this with @this",
          "body": [
            "`/** @this {HTMLElement} */` above the function gives `this` a type. Calling the function some other way, without the right `this`, is then reported."
          ],
          "examples": [
            "errors/ts2683-fixed"
          ]
        },
        {
          "id": "current-target",
          "heading": "Or use the event instead of this",
          "body": [
            "`event.currentTarget` is the element the listener is on. It is typed `EventTarget | null`, so check it with `instanceof HTMLElement` before using element properties. This also works in arrow functions, which have no `this` of their own."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A function that assigns to `this.something` is treated as a constructor function in a `.js` file, and `this` inside it is not reported.",
        "At the top level of a module, `this` is `undefined`; an arrow function there that uses `this` gets a different error (the value may be undefined) rather than TS2683."
      ],
      "related": [
        "tags/this",
        "types/this-parameter",
        "config/no-implicit-this",
        "config/strict"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @this",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#this",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: noImplicitThis",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitThis",
          "publisher": "TypeScript"
        },
        {
          "title": "Event: currentTarget property",
          "url": "https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2307",
      "slug": "ts2307",
      "code": 2307,
      "title": "TS2307: An import the checker cannot resolve",
      "message": "Cannot find module '{0}' or its corresponding type declarations.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "moduleResolution",
          "effect": "depends"
        },
        {
          "option": "paths",
          "effect": "depends"
        }
      ],
      "summary": "TS2307 means an import path resolves to nothing the checker can read: a package not installed, a typo, or a CSS or image file. Install it or declare the module.",
      "intro": [
        "`error TS2307: Cannot find module '@example/price-format' or its corresponding type declarations.` is reported when an `import` (or `require`, or `import()` type) names something module resolution cannot find, as a JavaScript or TypeScript file, a package, or a declaration.",
        "Three situations cover most cases: the package is not installed (or not in this folder's `node_modules`), the path has a typo, or the import is for a non-JavaScript file such as `./cart.module.css` that a bundler handles and the checker cannot read."
      ],
      "cause": [
        "The package is missing from `node_modules`: not installed, installed in another workspace, or removed.",
        "A relative path is wrong (a typo, a moved file, a different case on a case-sensitive file system).",
        "The import is for a file type the checker does not understand (CSS, images, SVG) and nothing declares what it exports.",
        "A path alias that the bundler understands (`@/components`) is not in the config's `paths`."
      ],
      "examples": [
        "errors/ts2307-missing"
      ],
      "fixes": [
        {
          "id": "install-or-declare",
          "heading": "Install the package; declare the file types the bundler handles",
          "body": [
            "For a package, install it (`npm install`) in the folder the config belongs to; if it ships JavaScript only, see [TS7016](/errors/ts7016/). For CSS modules and other assets, add a wildcard module declaration in a `.d.ts` file that `include` matches, as the fixed example does for `*.module.css`."
          ],
          "examples": [
            "errors/ts2307-fixed"
          ]
        },
        {
          "id": "paths",
          "heading": "Mirror bundler aliases in paths",
          "body": [
            "If the bundler resolves `@/...` to `src/...`, add the same mapping under [`paths`](/config/paths/) in `jsconfig.json`. The checker never reads the bundler's config."
          ]
        }
      ],
      "sections": [
        {
          "id": "side-effect-imports",
          "heading": "Side-effect imports",
          "body": [
            "`import \"./reset.css\";`, an import with no names, is not reported by default in TypeScript 5.9, even when nothing can be found. The option [`noUncheckedSideEffectImports`](/config/no-unchecked-side-effect-imports/) turns that check on."
          ]
        }
      ],
      "gotchas": [
        "A `types` list in `jsconfig.json` does not stop imports from finding `@types` packages; it only limits which ones load as globals.",
        "When `module` is set to an ES year without `moduleResolution`, packages in `node_modules` are not looked up the usual way and the error is [TS2792](/errors/ts2792/), which says so.",
        "Relative imports under `nodenext` without an extension are [TS2835](/errors/ts2835/), not TS2307."
      ],
      "related": [
        "errors/ts7016",
        "errors/ts2792",
        "errors/ts2835",
        "config/paths",
        "config/module-resolution",
        "config/no-unchecked-side-effect-imports"
      ],
      "sources": [
        {
          "title": "Modules Reference: Ambient modules (pattern ambient modules)",
          "url": "https://www.typescriptlang.org/docs/handbook/modules/reference.html#ambient-modules",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Modules Reference: The moduleResolution compiler option",
          "url": "https://www.typescriptlang.org/docs/handbook/modules/reference.html#the-moduleresolution-compiler-option",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2305",
      "slug": "ts2305",
      "code": 2305,
      "title": "TS2305: Importing a name the module does not export",
      "message": "Module '{0}' has no exported member '{1}'.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 2724,
          "message": "'{0}' has no exported member named '{1}'. Did you mean '{2}'?"
        }
      ],
      "summary": "TS2305 means a named import asks for something the module does not export; TS2724 adds a spelling suggestion. Fix the name, or export it from the module.",
      "intro": [
        "`error TS2305: Module '\"./format.js\"' has no exported member 'formatDate'.` is reported for `import { formatDate } from \"./format.js\"` when `format.js` exports no `formatDate`. If an export with a similar name exists, the error is TS2724 instead and suggests it: `'\"./format.js\"' has no exported member named 'formatPrise'. Did you mean 'formatPrice'?`",
        "At run time in Node.js the same import fails before any code runs (`SyntaxError: The requested module './format.js' does not provide an export named 'formatDate'`), so the checker is reporting a real crash early."
      ],
      "cause": [
        "The name is misspelled (TS2724 when the checker can suggest the right one).",
        "The function exists but was never exported, or was renamed in the module.",
        "The module exports it as its default export; that case has its own message, [TS2614](/errors/ts2614/)."
      ],
      "examples": [
        "errors/ts2305-missing-export"
      ],
      "fixes": [
        {
          "id": "match",
          "heading": "Import a name the module exports, or export it",
          "body": [
            "Fix the spelling, or add `export` to the function in the module. In the editor, completions inside the braces of an import list the module's exports."
          ],
          "examples": [
            "errors/ts2305-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "In a `.js` module every top-level `@typedef` is exported too, so a typedef can be imported by name with `@import`. A type imported in a regular `import` statement is a different error ([TS18042](/errors/ts18042/)), because a JavaScript import has to name a value."
      ],
      "related": [
        "errors/ts2614",
        "errors/ts2694",
        "tags/import",
        "errors/ts2307"
      ],
      "sources": [
        {
          "title": "Modules Reference",
          "url": "https://www.typescriptlang.org/docs/handbook/modules/reference.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "import",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2614",
      "slug": "ts2614",
      "code": 2614,
      "title": "TS2614: A named import of a default export",
      "message": "Module '{0}' has no exported member '{1}'. Did you mean to use 'import {1} from {0}' instead?",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 2613,
          "message": "Module '{0}' has no default export. Did you mean to use 'import { {1} } from {0}' instead?"
        }
      ],
      "summary": "TS2614 means import { name } was used for a default export; TS2613 is the reverse, a default import of named exports. Match the import to the export.",
      "intro": [
        "`error TS2614: Module '\"./slugify.js\"' has no exported member 'slugify'. Did you mean to use 'import slugify from \"./slugify.js\"' instead?` is reported when the braces of a named import ask for a name that the module exports only as its default. TS2613 is the opposite mistake: `import formatPrice from \"./format.js\"` for a module with named exports and no default.",
        "Both messages already contain the fix. They are common when a module changes from `export default` to named exports (or back), and when code moves between CommonJS habits and ES modules."
      ],
      "cause": [
        "The module uses `export default function slugify` and the import says `import { slugify }` (TS2614).",
        "The module uses `export function formatPrice` and the import says `import formatPrice` (TS2613)."
      ],
      "examples": [
        "errors/ts2614-default-vs-named"
      ],
      "fixes": [
        {
          "id": "match",
          "heading": "Write the import the way the module exports",
          "body": [
            "Default export: `import slugify from \"./slugify.js\"` (any local name works). Named export: `import { formatPrice } from \"./format.js\"`."
          ],
          "examples": [
            "errors/ts2614-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The TS2613 message names the module by its resolved path without the extension (tsc prints the full path; on this site examples live at `/project`), so its suggested import is not a path to copy. Keep your original specifier.",
        "Importing a CommonJS package's default export is a different question, governed by `esModuleInterop`; see [TS1259](/errors/ts1259/)."
      ],
      "related": [
        "errors/ts2305",
        "errors/ts1259",
        "config/es-module-interop"
      ],
      "sources": [
        {
          "title": "export",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "Modules Reference",
          "url": "https://www.typescriptlang.org/docs/handbook/modules/reference.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2792",
      "slug": "ts2792",
      "code": 2792,
      "title": "TS2792: Packages not found because module resolution is classic",
      "message": "Cannot find module '{0}'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option?",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "moduleResolution",
          "effect": "depends"
        },
        {
          "option": "module",
          "effect": "depends"
        }
      ],
      "summary": "TS2792 means module set to an ES year without moduleResolution left TypeScript 5.9 on its old classic lookup, which misses most packages. Set moduleResolution.",
      "intro": [
        "`error TS2792: Cannot find module 'ajv'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option?` is reported for a package import that would resolve under Node.js rules but fails under the resolution mode the config is using. The message is a hint that the mode is the problem.",
        "The usual cause is a `jsconfig.json` with `\"module\": \"es2022\"` (or `esnext`) and no `moduleResolution`. In TypeScript 5.9 that combination falls back to `classic`, a lookup from before npm packages were the norm: relative imports work, packages that ship their own types are not found. (`@types` packages are still found, which is why the error can appear for one package and not another.)"
      ],
      "cause": [
        "`module` is `es2015` to `esnext` and `moduleResolution` is not set, so it defaults to `classic`.",
        "`moduleResolution` is set to `classic` explicitly in an old config."
      ],
      "examples": [
        "errors/ts2792-classic"
      ],
      "fixes": [
        {
          "id": "set-resolution",
          "heading": "Set moduleResolution, or use module nodenext",
          "body": [
            "For code a bundler builds, add `\"moduleResolution\": \"bundler\"`. For code Node.js runs directly, use `\"module\": \"nodenext\"`, which implies `moduleResolution: \"nodenext\"`. Either way packages in `node_modules` resolve the way the runtime or bundler resolves them."
          ],
          "examples": [
            "errors/ts2792-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`bundler` resolution accepts imports without file extensions; Node.js itself does not. Pick the one that matches what runs the code.",
        "If the import is an alias your bundler defines, the second half of the hint applies: add it to [`paths`](/config/paths/)."
      ],
      "related": [
        "config/module-resolution",
        "config/module",
        "errors/ts2307",
        "errors/ts2835",
        "config/paths"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: moduleResolution",
          "url": "https://www.typescriptlang.org/tsconfig/#moduleResolution",
          "publisher": "TypeScript"
        },
        {
          "title": "Modules Reference: classic",
          "url": "https://www.typescriptlang.org/docs/handbook/modules/reference.html#classic",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts1259",
      "slug": "ts1259",
      "code": 1259,
      "title": "TS1259: A default import of a CommonJS module without interop",
      "message": "Module '{0}' can only be default-imported using the '{1}' flag",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "esModuleInterop",
          "effect": "off"
        },
        {
          "option": "allowSyntheticDefaultImports",
          "effect": "off"
        },
        {
          "option": "module",
          "effect": "depends"
        }
      ],
      "summary": "TS1259 means import x from a CommonJS package (export =) without esModuleInterop or allowSyntheticDefaultImports. A jsconfig.json allows it by default.",
      "intro": [
        "`error TS1259: Module '...express/index' can only be default-imported using the 'allowSyntheticDefaultImports' flag` is reported for `import express from \"express\"` when the package is CommonJS (its types use `export =`) and the config does not allow treating `module.exports` as a default export. The flag named in the message is the one to turn on.",
        "A file named `jsconfig.json` turns `allowSyntheticDefaultImports` on by default, and `module: \"nodenext\"` implies `esModuleInterop`, so JavaScript projects mostly meet this error in a `tsconfig.json` with `allowJs`, or in a config that switches the default off. The example does the latter."
      ],
      "cause": [
        "The imported package is CommonJS and its types say `export =` (Express, many older packages).",
        "Neither `esModuleInterop` nor `allowSyntheticDefaultImports` is on, and `module` is not `node16` to `nodenext` (which imply interop)."
      ],
      "examples": [
        "errors/ts1259-default-import"
      ],
      "fixes": [
        {
          "id": "interop",
          "heading": "Turn on esModuleInterop",
          "body": [
            "`\"esModuleInterop\": true` makes default imports of CommonJS modules work the way Node.js and bundlers run them, and implies `allowSyntheticDefaultImports`. With `module: \"nodenext\"` it is already on."
          ],
          "examples": [
            "errors/ts1259-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`import * as express from \"express\"` also passes the checker without interop, but calling `express()` on a namespace import fails at run time in Node.js's ES modules. Turn interop on instead.",
        "The message names the module by its resolved path (tsc prints the full path; on this site examples live at `/project`)."
      ],
      "related": [
        "config/es-module-interop",
        "config/module",
        "recipes/type-an-express-handler",
        "errors/ts2614"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: esModuleInterop",
          "url": "https://www.typescriptlang.org/tsconfig/#esModuleInterop",
          "publisher": "TypeScript"
        },
        {
          "title": "TSConfig Reference: allowSyntheticDefaultImports",
          "url": "https://www.typescriptlang.org/tsconfig/#allowSyntheticDefaultImports",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2835",
      "slug": "ts2835",
      "code": 2835,
      "title": "TS2835: A relative import without its file extension",
      "message": "Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean '{0}'?",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "moduleResolution",
          "effect": "depends"
        },
        {
          "option": "module",
          "effect": "depends"
        }
      ],
      "alsoCovers": [
        {
          "code": 2834,
          "message": "Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Consider adding an extension to the import path."
        }
      ],
      "summary": "TS2835 and TS2834 mean an ES module imports ./file or ./folder without .js under nodenext, which Node.js does not resolve. Write the full path, or use bundler.",
      "intro": [
        "`error TS2835: Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './format.js'?` is reported for `import ... from \"./format\"` in an ES module under `nodenext` resolution. Node.js's ES module loader does not guess extensions or look for `index.js`, so the import would fail when the code runs.",
        "TS2834 is the same rule when the checker has no single suggestion, typically a folder import such as `\"./utils\"`, which Node.js would need written as `\"./utils/index.js\"`."
      ],
      "cause": [
        "The file is an ES module (a `.js` file in a package with `\"type\": \"module\"`, or a `.mjs` file) and `moduleResolution` is `node16` or `nodenext`.",
        "The import leaves out `.js`, or points at a folder and relies on `index.js`, habits from CommonJS and bundlers."
      ],
      "examples": [
        "errors/ts2835-no-extension"
      ],
      "fixes": [
        {
          "id": "full-path",
          "heading": "Write the path Node.js resolves",
          "body": [
            "Add the extension, `./format.js`, and spell out folder imports, `./utils/index.js`. In a JavaScript project the path is simply the real file name."
          ],
          "examples": [
            "errors/ts2835-fixed"
          ]
        },
        {
          "id": "bundler",
          "heading": "Or, if a bundler resolves your imports, use bundler resolution",
          "body": [
            "Code that only ever runs through Vite, webpack or another bundler can keep extensionless imports with `\"module\": \"preserve\"` and `\"moduleResolution\": \"bundler\"`. Do not use this for code Node.js runs directly."
          ],
          "examples": [
            "errors/ts2835-bundler"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "CommonJS files under `nodenext` (a package without `\"type\": \"module\"`) may still import without extensions, because `require` resolution adds them; only ES modules are held to the rule.",
        "A path with the `.js` extension works under every `moduleResolution` mode, `bundler` included, so writing extensions everywhere keeps code portable between the two."
      ],
      "related": [
        "config/module-resolution",
        "config/module",
        "start/node-esm",
        "errors/ts2307",
        "errors/ts2792"
      ],
      "sources": [
        {
          "title": "Modules Reference: node16, nodenext",
          "url": "https://www.typescriptlang.org/docs/handbook/modules/reference.html#node16-nodenext",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Node.js: ECMAScript modules, mandatory file extensions",
          "url": "https://nodejs.org/api/esm.html#mandatory-file-extensions",
          "publisher": "Node.js documentation"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts1378",
      "slug": "ts1378",
      "code": 1378,
      "title": "TS1378: Top-level await with an older module setting",
      "message": "Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', 'node18', 'node20', 'nodenext', or 'preserve', and the 'target' option is set to 'es2017' or higher.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "module",
          "effect": "depends"
        },
        {
          "option": "target",
          "effect": "depends"
        }
      ],
      "summary": "TS1378 means await at the top of a module, with module or target set too old for it, often because module is missing. Set module to nodenext or es2022.",
      "intro": [
        "`error TS1378: Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', ...` is reported for an `await` outside any function when the config's `module` or `target` does not allow it. The runtime may support top-level `await` perfectly well; the checker goes by the config.",
        "The common trap is a `jsconfig.json` that sets `target` but not `module`. TypeScript 5.9 then picks an older module format (`es2015` for a recent target, `commonjs` with no target at all), and both are outside the list in the message, even in a package with `\"type\": \"module\"`."
      ],
      "cause": [
        "`module` is not set, or is set to `commonjs`, `es2015` or `es2020`.",
        "`target` is below `es2017`, or not set (the 5.9 default is `es5`)."
      ],
      "examples": [
        "errors/ts1378-top-level-await"
      ],
      "fixes": [
        {
          "id": "module",
          "heading": "Set module to nodenext (or es2022)",
          "body": [
            "For Node.js, `\"module\": \"nodenext\"` with `\"type\": \"module\"` in `package.json` allows top-level `await` and implies a recent `target`. For a bundler, `\"module\": \"preserve\"` or `\"es2022\"` with `\"moduleResolution\": \"bundler\"`."
          ],
          "examples": [
            "errors/ts1378-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "In a CommonJS file under `nodenext` (a package without `\"type\": \"module\"`), top-level `await` is a different error, TS1309, because CommonJS cannot wait at the top level at all.",
        "The runtime has to load the file as a module too: a browser `<script>` without `type=\"module\"` cannot use top-level `await` whatever the config says."
      ],
      "related": [
        "config/module",
        "config/target",
        "start/node-esm",
        "errors/ts2583"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: module",
          "url": "https://www.typescriptlang.org/tsconfig/#module",
          "publisher": "TypeScript"
        },
        {
          "title": "TypeScript 3.8 release notes (top-level await)",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2580",
      "slug": "ts2580",
      "code": 2580,
      "title": "TS2580: Node.js globals without the Node.js types",
      "message": "Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "types",
          "effect": "depends"
        }
      ],
      "summary": "TS2580 means process, Buffer, module or another Node.js global is used and @types/node is not installed. Install it as a dev dependency.",
      "intro": [
        "TS2580, \"Cannot find name 'process'. Do you need to install type definitions for node?\", is reported when code uses a Node.js global and no declaration for it is loaded. TypeScript's own libraries describe the language and the browser, not Node.js; Node's globals come from the `@types/node` package, which is what the message's suggested command installs.",
        "The checker picks this message when the config has no `types` list. With a `types` list that leaves `node` out, the same problem is [TS2591](/errors/ts2591/), whose message adds \"and then add 'node' to the types field\"."
      ],
      "cause": [
        "`@types/node` is not installed in the project.",
        "The config has no `types` list (so every installed `@types` package would load if it were there)."
      ],
      "examples": [
        "errors/ts2580-no-node-types"
      ],
      "fixes": [
        {
          "id": "install",
          "heading": "Install @types/node",
          "body": [
            "Run `npm install --save-dev @types/node`, ideally the major version matching the Node.js you run. The fixed example has it available and names it in `types`, which is what the quick-start setups on this site do."
          ],
          "examples": [
            "errors/ts2580-fixed"
          ]
        }
      ],
      "sections": [
        {
          "id": "about-the-example",
          "heading": "About the example",
          "body": [
            "This site's build has `@types/node` installed, so the failing example points `typeRoots` at its own empty `node_modules/@types` folder to stand for a project without it. In your project you would simply not have the package."
          ]
        }
      ],
      "gotchas": [
        "`require` itself is not reported in a `.js` file, because the checker reads `require(...)` calls as imports; the module name is then reported if it cannot be found (TS2307 for `\"fs\"` without the Node.js types).",
        "`__dirname` and `__filename` are reported as plain [TS2304](/errors/ts2304/) without the hint. In ES modules they do not exist at all; Node.js offers `import.meta.dirname` and `import.meta.filename` instead (from version 20.11, per its documentation)."
      ],
      "related": [
        "errors/ts2591",
        "errors/ts2584",
        "config/types",
        "start/node-esm",
        "start/node-cjs"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: types",
          "url": "https://www.typescriptlang.org/tsconfig/#types",
          "publisher": "TypeScript"
        },
        {
          "title": "@types/node",
          "url": "https://www.npmjs.com/package/@types/node",
          "publisher": "npm"
        },
        {
          "title": "Node.js: import.meta.dirname",
          "url": "https://nodejs.org/api/esm.html#importmetadirname",
          "publisher": "Node.js documentation"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2591",
      "slug": "ts2591",
      "code": 2591,
      "title": "TS2591: Node.js globals with node missing from types",
      "message": "Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "types",
          "effect": "depends"
        }
      ],
      "summary": "TS2591 means a Node.js global is used and the config's types list does not include node. Add \"node\" to types (and install @types/node if needed).",
      "intro": [
        "TS2591, \"Cannot find name 'process'. ... and then add 'node' to the types field in your tsconfig.\", is reported for Node.js globals when the config has a `types` list. A `types` list loads only the packages it names, so `@types/node` stays out even when it is installed.",
        "The setups on this site start from `\"types\": []` for browser code and `\"types\": [\"node\"]` for Node.js; a Node.js file in a project set up for the browser gets this error. Without any `types` list the message would be [TS2580](/errors/ts2580/)."
      ],
      "cause": [
        "`compilerOptions.types` is set and does not include `\"node\"`.",
        "`@types/node` may also be missing; the message covers both steps."
      ],
      "examples": [
        "errors/ts2591-types-list"
      ],
      "fixes": [
        {
          "id": "add-node",
          "heading": "Add node to the types list",
          "body": [
            "Install `@types/node` if it is not there, then write `\"types\": [\"node\"]` (keeping any other names already in the list)."
          ],
          "examples": [
            "errors/ts2591-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Leaving `node` out on purpose is a good way to keep browser code free of Node.js globals; in a project with both, give the server folder its own config that extends the shared one and adds `node`.",
        "The message says \"tsconfig\" but means whichever config file you use, `jsconfig.json` included."
      ],
      "related": [
        "errors/ts2580",
        "config/types",
        "start/node-esm",
        "start/monorepo",
        "errors/ts2584"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: types",
          "url": "https://www.typescriptlang.org/tsconfig/#types",
          "publisher": "TypeScript"
        },
        {
          "title": "@types/node",
          "url": "https://www.npmjs.com/package/@types/node",
          "publisher": "npm"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7016",
      "slug": "ts7016",
      "code": 7016,
      "title": "TS7016: A package without type declarations",
      "message": "Could not find a declaration file for module '{0}'. '{1}' implicitly has an 'any' type.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        },
        {
          "option": "maxNodeModuleJsDepth",
          "effect": "off"
        }
      ],
      "summary": "TS7016 means an imported package ships JavaScript without types and the checker does not read it. Install @types, write a small .d.ts, or let it read the JS.",
      "intro": [
        "`error TS7016: Could not find a declaration file for module 'legacy-slugify'. '/project/node_modules/legacy-slugify/index.js' implicitly has an 'any' type.` is reported when an import resolves to a package's JavaScript but no type declarations: no `types` in its `package.json`, no `.d.ts` next to it, no `@types` package. Under `noImplicitAny` the resulting `any` is an error.",
        "A `jsconfig.json` makes this rarer than in TypeScript projects: it sets `maxNodeModuleJsDepth` to 2, so the checker reads the package's own JavaScript (and its JSDoc) for types. You meet TS7016 in a `tsconfig.json` with `allowJs`, with `maxNodeModuleJsDepth: 0` as in the example, or for packages deeper than the limit."
      ],
      "cause": [
        "The package publishes JavaScript only, and no `@types/<name>` package is installed.",
        "The checker is not reading packages' JavaScript: `maxNodeModuleJsDepth` is 0 (the `tsconfig.json` default) or the package is beyond the depth.",
        "`noImplicitAny` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts7016-untyped-package"
      ],
      "fixes": [
        {
          "id": "types-package",
          "heading": "Install the @types package, if there is one",
          "body": [
            "The message suggests `npm i --save-dev @types/<name>`. DefinitelyTyped publishes types for many JavaScript-only packages; a `types: []` list in your config does not stop the import from finding it."
          ],
          "examples": [
            "errors/ts7016-types-package"
          ]
        },
        {
          "id": "local-declaration",
          "heading": "Or write a small declaration file",
          "body": [
            "Write a `.d.ts` file with `declare module \"legacy-slugify\" { ... }` describing just the functions you use, matched by `include`. `declare module \"legacy-slugify\";` with no body also silences the error, but makes every import `any`."
          ],
          "examples": [
            "errors/ts7016-local-declaration"
          ]
        },
        {
          "id": "read-the-js",
          "heading": "Or let the checker read the package's JavaScript",
          "body": [
            "With the `jsconfig.json` default (`maxNodeModuleJsDepth` 2), the checker reads the package's files and takes types from their code and JSDoc. That works best for packages that are documented with JSDoc, like the one in this example."
          ],
          "examples": [
            "errors/ts7016-js-depth"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "When the checker reads a package's JavaScript, an untyped parameter inside the package is reported as [TS7006](/errors/ts7006/) against the package's own file under `noImplicitAny`, whether or not your code calls that function. A `.d.ts` or an `@types` package avoids that.",
        "The path in the message is the file the import resolved to (tsc prints the full path; on this site examples live at `/project`)."
      ],
      "related": [
        "config/max-node-module-js-depth",
        "config/types",
        "errors/ts2307",
        "config/skip-lib-check",
        "config/no-implicit-any"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: maxNodeModuleJsDepth",
          "url": "https://www.typescriptlang.org/tsconfig/#maxNodeModuleJsDepth",
          "publisher": "TypeScript"
        },
        {
          "title": "Consumption (installing @types packages)",
          "url": "https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts1543",
      "slug": "ts1543",
      "code": 1543,
      "title": "TS1543: A JSON import without the import attribute",
      "message": "Importing a JSON file into an ECMAScript module requires a 'type: \"json\"' import attribute when 'module' is set to '{0}'.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "module",
          "effect": "depends"
        }
      ],
      "alsoCovers": [
        {
          "code": 1544,
          "message": "Named imports from a JSON file into an ECMAScript module are not allowed when 'module' is set to '{0}'."
        }
      ],
      "summary": "TS1543 means an ES module imports a JSON file without with { type: \"json\" } under module nodenext. Add the attribute; TS1544 says to use the default import.",
      "intro": [
        "Node.js loads a JSON file from an ES module only with an import attribute: `import config from \"./config.json\" with { type: \"json\" };`. Under `module: \"nodenext\"`, TypeScript holds JavaScript to the same rule and reports a JSON import without the attribute as TS1543.",
        "Node.js also gives a JSON module a default export only, so a named import (`import { port } from \"./config.json\"`) is TS1544 even with the attribute. Both checks arrived with [TypeScript 5.7](/typescript/5-7/), per its release notes."
      ],
      "cause": [
        "A JSON import in an ES module (a `.mjs` file, or a `.js` file in a package with `\"type\": \"module\"`) has no `with { type: \"json\" }`.",
        "A named import from a JSON file, which Node.js does not support."
      ],
      "examples": [
        "errors/ts1543-json-without-attribute"
      ],
      "fixes": [
        {
          "id": "attribute",
          "heading": "Add the attribute and import the default",
          "body": [
            "Write `with { type: \"json\" }` after the module name and read the values from the default export. TypeScript types the import from the file's contents."
          ],
          "examples": [
            "errors/ts1543-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "CommonJS files load JSON with `require(\"./config.json\")` and need no attribute.",
        "Bundlers and `moduleResolution: \"bundler\"` do not require the attribute, so the error appears when a project moves to `nodenext` to match Node.js.",
        "The older `assert { type: \"json\" }` spelling is [TS2880](/errors/ts2880/) under `nodenext`."
      ],
      "related": [
        "recipes/import-json-files",
        "config/resolve-json-module",
        "config/module",
        "errors/ts2880",
        "typescript/5-7"
      ],
      "sources": [
        {
          "title": "TypeScript 5.7: checks for import attributes in nodenext",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-7.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Modules: JSON modules",
          "url": "https://nodejs.org/api/esm.html#json-modules",
          "publisher": "Node.js documentation"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts2880",
      "slug": "ts2880",
      "code": 2880,
      "title": "TS2880: assert on an import, where with is required",
      "message": "Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.",
      "category": "Modules and imports",
      "tsCategory": "error",
      "flags": [
        {
          "option": "module",
          "effect": "depends"
        }
      ],
      "summary": "TS2880 means an import uses the old assert { type: \"json\" } syntax under module nodenext. Write with instead of assert; nothing else changes.",
      "intro": [
        "Import assertions (`assert { type: \"json\" }`) were replaced in the JavaScript standard by import attributes (`with { type: \"json\" }`). Per the [TypeScript 5.8 page](/typescript/5-8/), Node.js 22 no longer accepts `assert`, and under `module: \"nodenext\"` TypeScript reports it as TS2880.",
        "The fix is one word, and the rest of the import stays as it is."
      ],
      "cause": [
        "Code written for Node.js 16 to 20, or copied from older documentation, that still says `assert`."
      ],
      "examples": [
        "errors/ts2880-assert"
      ],
      "fixes": [
        {
          "id": "with",
          "heading": "Write with instead of assert",
          "body": [
            "`import config from \"./config.json\" with { type: \"json\" };` is accepted by current Node.js versions and by TypeScript under every module setting that allows attributes."
          ],
          "examples": [
            "errors/ts2880-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "With `module: \"esnext\"` or `\"preserve\"`, TypeScript 5.9 still accepts `assert`, so the error appears when a project moves to `nodenext`.",
        "The same JSON import without any attribute is [TS1543](/errors/ts1543/) under `nodenext`."
      ],
      "related": [
        "errors/ts1543",
        "recipes/import-json-files",
        "config/module",
        "typescript/5-8"
      ],
      "sources": [
        {
          "title": "TypeScript 5.8 release notes",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-8.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Modules: import attributes",
          "url": "https://nodejs.org/api/esm.html#import-attributes",
          "publisher": "Node.js documentation"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts8010",
      "slug": "ts8010",
      "code": 8010,
      "title": "TS8010: TypeScript annotations in a .js file",
      "message": "Type annotations can only be used in TypeScript files.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 8004,
          "message": "Type parameter declarations can only be used in TypeScript files."
        }
      ],
      "summary": "TS8010 means TypeScript syntax such as name: string was written in a .js file, usually pasted from a .ts file. Move the types into JSDoc tags.",
      "intro": [
        "`error TS8010: Type annotations can only be used in TypeScript files.` is reported for every `: Type` annotation in a `.js` file: on parameters, return types, variables and class fields. TS8004 is the same for a type parameter list (`function first<T>(...)`). The code would also fail to run, because JavaScript has no such syntax; Node.js's type stripping only applies to `.ts` files.",
        "This is what happens when code is copied from a TypeScript project or an answer written for one. Every annotation has a JSDoc spelling, and the checker treats them the same way: `@param` and `@returns` for functions, `@type` for variables, `@template` for type parameters."
      ],
      "cause": [
        "TypeScript code was pasted into a `.js` file, or a `.ts` file was renamed to `.js`.",
        "The editor is not misconfigured: it checks a `.js` file as JavaScript, as it should, so the TypeScript syntax is what has to change."
      ],
      "examples": [
        "errors/ts8010-annotations"
      ],
      "fixes": [
        {
          "id": "jsdoc",
          "heading": "Write the same types in JSDoc",
          "body": [
            "Move each annotation into a comment: `@param {number[]} prices` and `@returns {number}` above the function, `/** @type {number} */` above the variable, `@template T` for the type parameter. The fixed example's TypeScript tab shows the original next to it."
          ],
          "examples": [
            "errors/ts8010-fixed"
          ]
        },
        {
          "id": "rename",
          "heading": "Or make the file TypeScript",
          "body": [
            "If the project is meant to have `.ts` files, rename the file and make sure a `tsconfig.json` includes it. A JavaScript project that wants types without a build step keeps `.js` and JSDoc."
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Other TypeScript-only syntax has its own codes in the same family: `as` is [TS8016](/errors/ts8016/), `!` is [TS8013](/errors/ts8013/), `interface` and `enum` are [TS8006](/errors/ts8006/), `type X =` is [TS8008](/errors/ts8008/), `private` and `readonly` are [TS8009](/errors/ts8009/), parameter properties are TS8012.",
        "A definite assignment annotation (`let total!: number`) is TS8010 too; in JSDoc, initialize the variable instead."
      ],
      "related": [
        "tags/param",
        "tags/returns",
        "tags/type",
        "tags/template",
        "errors/ts8016",
        "errors/ts8006"
      ],
      "sources": [
        {
          "title": "JSDoc Reference",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Type Checking JavaScript Files",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts8016",
      "slug": "ts8016",
      "code": 8016,
      "title": "TS8016: An as cast in a .js file",
      "message": "Type assertion expressions can only be used in TypeScript files.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 8037,
          "message": "Type satisfaction expressions can only be used in TypeScript files."
        }
      ],
      "summary": "TS8016 and TS8037 mean as or satisfies was written in a .js file. The JSDoc spellings are a parenthesized @type cast and the @satisfies tag.",
      "intro": [
        "`error TS8016: Type assertion expressions can only be used in TypeScript files.` is reported for `expr as Type` in a `.js` file, and TS8037 for `expr satisfies Type`. Both are TypeScript operators; in JavaScript they are syntax errors.",
        "JSDoc has an equivalent for each. A cast is a `@type` comment directly before a parenthesized expression: `/** @type {HTMLInputElement} */ (document.querySelector(\"#quantity\"))`. `@satisfies` is a tag on the declaration and checks the value without changing its type."
      ],
      "cause": [
        "TypeScript code with `as` or `satisfies` was pasted into a `.js` file."
      ],
      "examples": [
        "errors/ts8016-as"
      ],
      "fixes": [
        {
          "id": "jsdoc-cast",
          "heading": "Use a JSDoc cast and @satisfies",
          "body": [
            "The parentheses are required: `/** @type {T} */ (value)` casts, while a `@type` comment without them annotates the declaration instead. `/** @satisfies {ServerConfig} */` above `export const config = { ... }` checks the object against the type and keeps its own, narrower type, exactly as `satisfies` does."
          ],
          "examples": [
            "errors/ts8016-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The older angle-bracket assertion (`<HTMLElement>value`) is read as JSX in a `.js` file and produces JSX errors instead of TS8016; it has no JavaScript form either, so use the JSDoc cast.",
        "`as const` has a JSDoc form too: `/** @type {const} */ ([10, 20])`."
      ],
      "related": [
        "types/type-casts",
        "tags/satisfies",
        "types/satisfies",
        "types/const-assertions",
        "errors/ts8013"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: Casts",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#casts",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @satisfies",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#satisfies",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts8013",
      "slug": "ts8013",
      "code": 8013,
      "title": "TS8013: The ! operator in a .js file",
      "message": "Non-null assertions can only be used in TypeScript files.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS8013 means TypeScript's postfix ! (\"this is not null\") was written in a .js file. Check the value instead, or cast it with a JSDoc @type.",
      "intro": [
        "`error TS8013: Non-null assertions can only be used in TypeScript files.` is reported for a postfix `!` such as `document.getElementById(\"app\")!` in a `.js` file. In TypeScript the `!` tells the checker a value is not `null` or `undefined`; JavaScript has no such operator.",
        "Without it, the original problem returns: the value may be `null` ([TS2531](/errors/ts2531/) or [TS18047](/errors/ts18047/)). Either prove it is there with a check, which also helps when the page changes, or state it with a cast."
      ],
      "cause": [
        "TypeScript code using `!` was pasted into a `.js` file."
      ],
      "examples": [
        "errors/ts8013-non-null"
      ],
      "fixes": [
        {
          "id": "check-or-cast",
          "heading": "Check the value, or cast it",
          "body": [
            "`if (!root) throw new Error(...)` narrows the variable and fails with a clear message if the element is ever missing. `/** @type {HTMLElement} */ (document.querySelector(\"footer\"))` is the JSDoc version of the assertion, for elements the markup always has."
          ],
          "examples": [
            "errors/ts8013-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`!` before a value (`!root`) is ordinary JavaScript negation; only the postfix form is TypeScript.",
        "In JSDoc types, a leading `!` (`{!HTMLElement}`) is accepted but does not remove `null`, so it is no substitute; see the [non-null assertions page](/types/non-null-assertions/)."
      ],
      "related": [
        "types/non-null-assertions",
        "types/type-casts",
        "errors/ts2531",
        "errors/ts18047"
      ],
      "sources": [
        {
          "title": "Everyday Types: Non-null Assertion Operator",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#non-null-assertion-operator-postfix-",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: Casts",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#casts",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts8006",
      "slug": "ts8006",
      "code": 8006,
      "title": "TS8006: interface, enum or namespace in a .js file",
      "message": "'{0}' declarations can only be used in TypeScript files.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS8006 means an interface, enum or namespace declaration was written in a .js file. Use @typedef for shapes and a frozen object with @enum for values.",
      "intro": [
        "`error TS8006: 'interface' declarations can only be used in TypeScript files.` is reported for `interface`, `enum` and `namespace` (or `module`) declarations in a `.js` file. The `{0}` in the message is the keyword.",
        "An `interface` only describes a shape, so in JavaScript it becomes a `@typedef`. An `enum` also creates a value at run time, so it becomes a real object: a frozen object for the values, plus `@enum` or a union of string literals for the type."
      ],
      "cause": [
        "TypeScript declarations were pasted into a `.js` file."
      ],
      "examples": [
        "errors/ts8006-interface-enum"
      ],
      "fixes": [
        {
          "id": "typedef-and-object",
          "heading": "A @typedef for the shape, an object for the values",
          "body": [
            "Write the interface as `@typedef {object} LineItem` with one `@property` per field. For the enum, `export const Status = Object.freeze({ ... })` with `/** @enum {string} */` gives a value you can import and a type for the members. A string literal union (`@typedef {\"pending\" | \"shipped\"} Status`) is often simpler when the values are only compared."
          ],
          "examples": [
            "errors/ts8006-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`@enum` types each member as the type in its tag (`string` here), not as the literal value; use a union `@typedef` when you need the exact strings checked.",
        "A namespace in JavaScript is just an object; see the [@namespace page](/tags/namespace/) for what the checker reads."
      ],
      "related": [
        "tags/typedef",
        "tags/enum",
        "tags/property",
        "tags/namespace",
        "types/literal-types",
        "errors/ts8008"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @typedef, @callback, and @param",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#typedef-callback-and-param",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: @enum",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#enum",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts8008",
      "slug": "ts8008",
      "code": 8008,
      "title": "TS8008: A type alias in a .js file",
      "message": "Type aliases can only be used in TypeScript files.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS8008 means type Name = ... was written in a .js file. The JSDoc spelling is a @typedef with the same type in braces, usable from any file.",
      "intro": [
        "`error TS8008: Type aliases can only be used in TypeScript files.` is reported for a `type Status = ...` declaration in a `.js` file. It is TypeScript syntax, and JavaScript would reject it.",
        "The JSDoc equivalent is `/** @typedef {...} Status */`: the type inside the braces is written exactly as on the right of the `=`. In a module, the typedef is exported automatically and other files can import it with `@import`."
      ],
      "cause": [
        "A type alias was pasted from TypeScript code."
      ],
      "examples": [
        "errors/ts8008-type-alias"
      ],
      "fixes": [
        {
          "id": "typedef",
          "heading": "Write it as a @typedef",
          "body": [
            "Move the type into a `@typedef` comment, keeping the name. Unions, object types, generics (with `@template`) and utility types all work inside the braces."
          ],
          "examples": [
            "errors/ts8008-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A `@typedef` is visible in the whole file regardless of where it is written, like a type alias; it does not need to come before its use.",
        "In a file that is a script rather than a module, a top-level `@typedef` is global to the project."
      ],
      "related": [
        "tags/typedef",
        "tags/import",
        "tags/template",
        "errors/ts8006",
        "types/union"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @typedef, @callback, and @param",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#typedef-callback-and-param",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Everyday Types: Type Aliases",
          "url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts8009",
      "slug": "ts8009",
      "code": 8009,
      "title": "TS8009: private, readonly or another TypeScript modifier in a .js file",
      "message": "The '{0}' modifier can only be used in TypeScript files.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS8009 means a TypeScript-only modifier (private, public, readonly, abstract, declare, ?) was used in a .js file. Use #private fields or the JSDoc tags.",
      "intro": [
        "`error TS8009: The 'private' modifier can only be used in TypeScript files.` is reported for the TypeScript keywords that modify a declaration: `private`, `protected`, `public`, `readonly`, `abstract`, `override`, `declare`, and the `?` that marks an optional parameter or property.",
        "JavaScript has its own private fields (`#balance`), enforced at run time, and JSDoc has tags for the rest (`@private`, `@protected`, `@readonly`, `@override`, brackets for optional parameters), which the checker enforces."
      ],
      "cause": [
        "Class members or parameters were written with TypeScript modifiers, usually in code pasted from a `.ts` file."
      ],
      "examples": [
        "errors/ts8009-modifiers"
      ],
      "fixes": [
        {
          "id": "js-and-jsdoc",
          "heading": "Use #private fields and JSDoc tags",
          "body": [
            "`#balance` makes the field private in the running code, not only to the checker; add a getter if callers need to read it. For read-only fields, put `/** @readonly */` on the line above; for optional parameters, write `@param {string} [note]`."
          ],
          "examples": [
            "errors/ts8009-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Parameter properties (`constructor(private bank)`) are a separate code, TS8012; assign `this.bank = bank` in the constructor instead.",
        "`@private` and `#private` differ: the tag is checked by tsc only ([TS2341](/errors/ts2341/) on misuse), while `#` fields cannot be reached from outside the class at run time."
      ],
      "related": [
        "tags/private",
        "tags/readonly",
        "tags/override",
        "errors/ts2341",
        "errors/ts2540"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: Property Modifiers",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#property-modifiers",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Private elements (#)",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts8024",
      "slug": "ts8024",
      "code": 8024,
      "title": "TS8024: A @param tag that names no parameter",
      "message": "JSDoc '@param' tag has name '{0}', but there is no parameter with that name.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS8024 means a @param tag's name matches no parameter, usually after a rename. The parameter is then untyped too (TS7006). Rename the tag.",
      "intro": [
        "`error TS8024: JSDoc '@param' tag has name 'name', but there is no parameter with that name.` is reported when a `@param` tag names a parameter the function does not have. JSDoc matches tags to parameters by name, so a renamed parameter loses its type silently in plain JSDoc tools; the checker reports it.",
        "Two errors usually appear together: TS8024 on the tag, and [TS7006](/errors/ts7006/) on the parameter, which now has no type. TS8024 is reported inside the comment, on the tag's line."
      ],
      "cause": [
        "The parameter was renamed and the tag was not (or the other way round).",
        "A tag documents a destructured parameter's property with a plain name instead of `options.name`."
      ],
      "examples": [
        "errors/ts8024-param-name"
      ],
      "fixes": [
        {
          "id": "rename",
          "heading": "Give the tag the parameter's name",
          "body": [
            "Change `@param {string} name` to `@param {string} fullName`. Editors that run TypeScript's language service rename both when you rename the parameter with the rename command instead of by hand."
          ],
          "examples": [
            "errors/ts8024-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "For a function that reads `arguments` instead of named parameters, the checker adds a hint to a similar message (TS8029): the tag would match `arguments` if it had an array type.",
        "The example writes the comment on one line so this site's marker can sit above the tag; tsc reports the tag's line in a multi-line comment just the same."
      ],
      "related": [
        "tags/param",
        "errors/ts7006",
        "errors/ts7031"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @param and @returns",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "@param on jsdoc.app",
          "url": "https://jsdoc.app/tags-param",
          "publisher": "JSDoc"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts8023",
      "slug": "ts8023",
      "code": 8023,
      "title": "TS8023: An @extends tag that does not match the extends clause",
      "message": "JSDoc '@{0} {1}' does not match the 'extends {2}' clause.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS8023 means a class's @extends (or @augments) tag names a different class from its extends clause. The tag should repeat the class, adding type arguments.",
      "intro": [
        "`error TS8023: JSDoc '@extends Collection' does not match the 'extends Queue' clause.` is reported when the class named in an `@extends` (or `@augments`) tag is not the one in the `extends` clause. The tag's job in JavaScript is to supply type arguments to a generic base class, `@extends {Queue<string>}`, which the `extends` clause has no syntax for; it cannot change which class is extended.",
        "It usually follows a refactor: the base class changed and the tag above the subclass still names the old one. The error is reported inside the JSDoc comment."
      ],
      "cause": [
        "The `extends` clause was changed and the `@extends` tag was not.",
        "The tag names an interface or type, hoping to describe the class; use `@implements` for that."
      ],
      "examples": [
        "errors/ts8023-extends"
      ],
      "fixes": [
        {
          "id": "match",
          "heading": "Name the same class, with its type arguments",
          "body": [
            "Write `@extends {Queue<string>}` above `class Inbox extends Queue`. The subclass then knows that `waiting` holds strings."
          ],
          "examples": [
            "errors/ts8023-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "An `@extends` tag on a class with no `extends` clause is ignored without any error, so it cannot add a base class.",
        "Without the tag, a generic base class's type parameters are `any` in JavaScript, which is why the tag exists."
      ],
      "related": [
        "tags/extends",
        "tags/implements",
        "tags/template",
        "types/generic-classes"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @extends",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#extends",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Type Checking JavaScript Files: Unspecified type parameters default to any",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#unspecified-type-parameters-default-to-any",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts1247",
      "slug": "ts1247",
      "code": 1247,
      "title": "TS1247: An initializer in a type literal, often a Closure = in JSDoc",
      "message": "A type literal property cannot have an initializer.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS1247 in JSDoc usually means an old Closure-style optional marker, unit: string=, inside an object type. Write unit?: string instead.",
      "intro": [
        "Closure Compiler marked an optional parameter with a trailing `=` (`{string=}`), and older JSDoc carries the habit into object types: `{{ street: string, unit: string= }}`. TypeScript reads the `=` as the start of an initializer, which a type cannot have, and reports TS1247, usually together with TS1109 (\"Expression expected\").",
        "The property stays required, so objects that leave it out then fail too (TS2741 in the example). In a `.ts` file the same error comes from writing `= value` inside an `interface` or type literal."
      ],
      "cause": [
        "A Closure-style `=` after a property type inside a JSDoc object type.",
        "A default value written into a type instead of into the code."
      ],
      "examples": [
        "errors/ts1247-postfix-equals"
      ],
      "fixes": [
        {
          "id": "optional",
          "heading": "Mark the property optional with ?",
          "body": [
            "Write `unit?: string`. Put a default value in the code that reads the property (`const { unit = \"\" } = address`), not in the type."
          ],
          "examples": [
            "errors/ts1247-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The `=` form is accepted for a whole parameter type, `@param {string=} unit`, in TypeScript 5.9. TypeScript 7.0 drops much of the Closure syntax, so `@param {string} [unit]` is the safer spelling ([Closure syntax](/types/closure-syntax/))."
      ],
      "related": [
        "types/object-shapes",
        "types/closure-syntax",
        "types/optional-parameters",
        "guides/jsdoc-quirks",
        "errors/ts2741"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts18042",
      "slug": "ts18042",
      "code": 18042,
      "title": "TS18042: A type imported with import in a .js file",
      "message": "'{0}' is a type and cannot be imported in JavaScript files. Use '{1}' in a JSDoc type annotation.",
      "category": "JavaScript files only",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS18042 means a .js file imports a type by name with an import statement. Types come in through @import or import() types; the import is a runtime one.",
      "intro": [
        "An `import` statement in a `.js` file is a real import: it runs when the module loads and needs a value at the other end. A `@typedef` or an `interface` from a `.d.ts` file is not a value, so `import { LineItem } from \"./types.js\"` is TS18042, and the message suggests the `import()` type form instead.",
        "Since TypeScript 5.5, the [`@import`](/tags/import/) tag says the same thing with the syntax of an import statement, and it disappears at run time."
      ],
      "cause": [
        "Code moved from a `.ts` file, where `import { Type }` is fine because the import is erased.",
        "An import of a name that used to be a value and is now only a type."
      ],
      "examples": [
        "errors/ts18042-import-type"
      ],
      "fixes": [
        {
          "id": "at-import",
          "heading": "Use @import for types",
          "body": [
            "`/** @import { LineItem } from \"./types.js\" */` brings the type into scope for every JSDoc tag in the file. On TypeScript before 5.5, write `import(\"./types.js\").LineItem` in the tags, or a `@typedef` that aliases it."
          ],
          "examples": [
            "errors/ts18042-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "This site's tests found TS18042 with and without `verbatimModuleSyntax`: it is about JavaScript files, not about that option.",
        "A name in `@import` that is never used is not checked at all, so a typo there stays hidden until a tag uses it."
      ],
      "related": [
        "tags/import",
        "types/import-types",
        "recipes/import-and-reexport-types",
        "config/verbatim-module-syntax"
      ],
      "sources": [
        {
          "title": "TypeScript 5.5: the @import tag",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "JSDoc Reference: import types",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#import-types",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts2341",
      "slug": "ts2341",
      "code": 2341,
      "title": "TS2341: Using a @private member from outside its class",
      "message": "Property '{0}' is private and only accessible within class '{1}'.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [],
      "alsoCovers": [
        {
          "code": 2445,
          "message": "Property '{0}' is protected and only accessible within class '{1}' and its subclasses."
        }
      ],
      "summary": "TS2341 and TS2445 mean code outside a class uses a member marked @private or @protected. Go through a public method, or use a real #private field.",
      "intro": [
        "`error TS2341: Property 'balanceCents' is private and only accessible within class 'Account'.` is reported when code outside a class reads or writes a member whose JSDoc says `@private`. TS2445 is the same for `@protected`, which also allows subclasses.",
        "These tags are enforced by the checker only. At run time the property is an ordinary public property, which is the difference from JavaScript's own `#private` fields: those cannot be reached from outside the class at all, and even writing `account.#balanceCents` outside the class is a syntax error in JavaScript."
      ],
      "cause": [
        "A member is tagged `@private` or `@protected` and is used from outside the class (or, for `@private`, from a subclass).",
        "The tag was added to an existing property that other code still uses directly."
      ],
      "examples": [
        "errors/ts2341-private"
      ],
      "fixes": [
        {
          "id": "public-api",
          "heading": "Use the class's public methods, or make the field truly private",
          "body": [
            "Change the outside code to call what the class offers (`deposit`), or add a method or getter for what it needs. If the member must never be touched from outside, `#balanceCents` enforces that in the running code too, and a getter can expose it read-only."
          ],
          "examples": [
            "errors/ts2341-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "In a constructor function (not a class), `@private` on a `this.x = ...` assignment is reported as TS2341 on that assignment itself, because only a class body counts as inside the class; use a class for private members.",
        "TypeScript's `private` keyword is not allowed in a `.js` file ([TS8009](/errors/ts8009/)); the tag is its JSDoc spelling."
      ],
      "related": [
        "tags/private",
        "tags/protected",
        "tags/public",
        "errors/ts8009",
        "errors/ts2540"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: Property Modifiers",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#property-modifiers",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Classes: Member Visibility",
          "url": "https://www.typescriptlang.org/docs/handbook/2/classes.html#member-visibility",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2540",
      "slug": "ts2540",
      "code": 2540,
      "title": "TS2540: Assigning to a read-only property",
      "message": "Cannot assign to '{0}' because it is a read-only property.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2540 means code assigns to a property typed read-only: a @readonly field, a frozen object, a Readonly type. Set it in the constructor or copy the object.",
      "intro": [
        "`error TS2540: Cannot assign to 'id' because it is a read-only property.` is reported when code writes to a property whose type says it cannot change. In JavaScript projects the read-only marking comes from three places: a `@readonly` tag on a class field, `Object.freeze` (whose result the checker types as `Readonly`), and `Readonly<...>` or `readonly` inside a JSDoc type.",
        "For frozen objects the error matches what the running code does: in a module (always strict mode) assigning to a frozen property throws a `TypeError`. For `@readonly` fields it is a promise the checker keeps for you."
      ],
      "cause": [
        "A `@readonly` field is assigned outside the constructor.",
        "A property of an `Object.freeze(...)` result is assigned.",
        "A value typed `Readonly<T>` (or with a `readonly` property) is modified."
      ],
      "examples": [
        "errors/ts2540-readonly"
      ],
      "fixes": [
        {
          "id": "constructor-or-copy",
          "heading": "Set it in the constructor, or make a changed copy",
          "body": [
            "A `@readonly` field may be assigned in the class's constructor, so values that differ per instance go in as constructor arguments. For frozen data, build a new object with spread, `{ ...SHIPPING, express: 10 }`, and leave the original alone."
          ],
          "examples": [
            "errors/ts2540-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Read-only is shallow: `Object.freeze` and `Readonly` protect the top-level properties, not the objects inside them.",
        "Arrays have their own spelling, `readonly string[]` or `ReadonlyArray<string>`, which removes `push` and the other mutating methods; see [read-only arrays](/types/readonly-arrays/)."
      ],
      "related": [
        "tags/readonly",
        "types/readonly",
        "types/readonly-arrays",
        "errors/ts2341"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @readonly",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#readonly",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Object.freeze()",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2564",
      "slug": "ts2564",
      "code": 2564,
      "title": "TS2564: A typed field the constructor never sets",
      "message": "Property '{0}' has no initializer and is not definitely assigned in the constructor.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [
        {
          "option": "strictPropertyInitialization",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS2564 means a class field has a @type that excludes undefined but no value and no assignment in the constructor. Initialize it or include undefined.",
      "intro": [
        "`error TS2564: Property 'userId' has no initializer and is not definitely assigned in the constructor.` is reported for a class field declared with a type (here `/** @type {string} */ userId;`) when neither the declaration nor the constructor gives it a value. Until something does, reading it gives `undefined`, which the type does not allow.",
        "The check is `strictPropertyInitialization`, part of `strict`. It applies to fields declared in the class body; a property created only by `this.x = ...` in the constructor is set by definition."
      ],
      "cause": [
        "A field has a `@type` that does not include `undefined`, no initializer, and no assignment in the constructor.",
        "The value is set later (in an `init` method, after an `await`), which the checker cannot follow."
      ],
      "examples": [
        "errors/ts2564-no-initializer"
      ],
      "fixes": [
        {
          "id": "initialize",
          "heading": "Set it in the constructor, or allow undefined in its type",
          "body": [
            "Take the value as a constructor parameter and assign it there, or give the field a starting value. If it really is empty for a while, say so: `/** @type {string | undefined} */ token;`, and handle the empty case where it is read."
          ],
          "examples": [
            "errors/ts2564-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Assignments inside methods the constructor calls (`this.reset()`) do not count; the checker only looks at the constructor body itself.",
        "A field with no `@type` and no value is [TS7008](/errors/ts7008/) instead, the implicit `any` error."
      ],
      "related": [
        "config/strict-property-initialization",
        "errors/ts7008",
        "tags/type",
        "config/strict"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: strictPropertyInitialization",
          "url": "https://www.typescriptlang.org/tsconfig/#strictPropertyInitialization",
          "publisher": "TypeScript"
        },
        {
          "title": "Classes: Fields",
          "url": "https://www.typescriptlang.org/docs/handbook/2/classes.html#fields",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts4119",
      "slug": "ts4119",
      "code": 4119,
      "title": "TS4119: An override without the @override tag",
      "message": "This member must have a JSDoc comment with an '@override' tag because it overrides a member in the base class '{0}'.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitOverride",
          "effect": "on"
        }
      ],
      "summary": "TS4119 means noImplicitOverride is on and a subclass method replaces a base class method without an @override tag. Add the tag above the method.",
      "intro": [
        "`error TS4119: This member must have a JSDoc comment with an '@override' tag because it overrides a member in the base class 'Shape'.` is reported, with `noImplicitOverride` on, for a subclass member that has the same name as a base class member and is not marked as an override. In a `.ts` file the message asks for the `override` keyword (TS4114); in a `.js` file it asks for the JSDoc tag.",
        "The point of the option is the other direction: once every override is marked, a base class method that is renamed or removed turns each `@override` below it into an error ([TS4122](/errors/ts4122/)) instead of silently leaving dead methods behind."
      ],
      "cause": [
        "`noImplicitOverride` is on (it is not part of `strict`).",
        "A subclass method or property has the same name as one in its base class and no `@override` tag."
      ],
      "examples": [
        "errors/ts4119-missing-override"
      ],
      "fixes": [
        {
          "id": "tag",
          "heading": "Add @override",
          "body": [
            "`/** @override */` on its own line above the method. If the method already has a JSDoc comment, add the tag to it."
          ],
          "examples": [
            "errors/ts4119-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "The comment must be attached to the member: a JSDoc comment on the same line as the class's opening brace is not attached to the method after it.",
        "Constructors are not overrides; `constructor` never needs the tag."
      ],
      "related": [
        "tags/override",
        "config/no-implicit-override",
        "errors/ts4122",
        "tags/extends"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @override",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#override",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: noImplicitOverride",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitOverride",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts4122",
      "slug": "ts4122",
      "code": 4122,
      "title": "TS4122: @override on a member the base class does not have",
      "message": "This member cannot have a JSDoc comment with an '@override' tag because it is not declared in the base class '{0}'.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS4122 means a member is tagged @override but the base class has no member of that name: a typo, a rename in the base, or a new method. Fix or drop the tag.",
      "intro": [
        "`error TS4122: This member cannot have a JSDoc comment with an '@override' tag because it is not declared in the base class 'Shape'.` is reported for an `@override` tag on a member that overrides nothing. It is checked whether or not `noImplicitOverride` is on.",
        "This is the check that makes `@override` worth writing: if the base class renames `area` to `surface`, every subclass `area` that says `@override` is reported, instead of quietly becoming an unrelated method."
      ],
      "cause": [
        "The member's name is misspelled, or the base class method was renamed or removed.",
        "The method is new in the subclass and was tagged by habit."
      ],
      "examples": [
        "errors/ts4122-not-in-base"
      ],
      "fixes": [
        {
          "id": "fix-or-remove",
          "heading": "Override a real member, or remove the tag",
          "body": [
            "Rename the method to the base class's name if it was meant to override, or drop `@override` from a method that is new in the subclass."
          ],
          "examples": [
            "errors/ts4122-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A class without an `extends` clause has no base class, so `@override` there is a different error, TS4121 (\"its containing class ... does not extend another class\")."
      ],
      "related": [
        "tags/override",
        "errors/ts4119",
        "config/no-implicit-override"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @override",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#override",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: noImplicitOverride",
          "url": "https://www.typescriptlang.org/tsconfig/#noImplicitOverride",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2578",
      "slug": "ts2578",
      "code": 2578,
      "title": "TS2578: A // @ts-expect-error with nothing to expect",
      "message": "Unused '@ts-expect-error' directive.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2578 means a // @ts-expect-error comment sits above a line that no longer has an error. Remove the comment; that is the directive doing its job.",
      "intro": [
        "`error TS2578: Unused '@ts-expect-error' directive.` is reported on a `// @ts-expect-error` comment when the line after it has no error. Unlike `// @ts-ignore`, which hides whatever is there, `@ts-expect-error` insists that an error exists, so it tells you when the reason for it is gone.",
        "In a JavaScript project this usually appears after a fix or an upgrade: the call that used to fail now type-checks, and the comment that silenced it is stale."
      ],
      "cause": [
        "The error the comment was written for has been fixed, by a code change, a better type, or a new version of a library's types.",
        "The comment is not directly above the line with the error (a blank line or another statement in between), so it applies to a line that is fine."
      ],
      "examples": [
        "errors/ts2578-unused-directive"
      ],
      "fixes": [
        {
          "id": "remove",
          "heading": "Remove the comment",
          "body": [
            "Delete the directive. Keep `@ts-expect-error` only where an error is the expected result, such as a test that a function rejects the wrong type."
          ],
          "examples": [
            "errors/ts2578-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Write the directive as a `//` comment on the line above. A `/* @ts-expect-error */` block comment at the end of a line of code does not cover that line: like the `//` form, it applies to the line after it; the [directive page](/config/ts-expect-error/) shows the placement rules.",
        "Text after the directive (`// @ts-expect-error -- reason`) is allowed and is a good place to say why."
      ],
      "related": [
        "config/ts-expect-error",
        "config/ts-ignore",
        "config/ts-check"
      ],
      "sources": [
        {
          "title": "TypeScript 3.9 release notes (// @ts-expect-error comments)",
          "url": "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html",
          "publisher": "TypeScript"
        },
        {
          "title": "Type Checking JavaScript Files",
          "url": "https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts6133",
      "slug": "ts6133",
      "code": 6133,
      "title": "TS6133: A variable, import or parameter that is never read",
      "message": "'{0}' is declared but its value is never read.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noUnusedLocals",
          "effect": "on"
        },
        {
          "option": "noUnusedParameters",
          "effect": "on"
        }
      ],
      "summary": "TS6133 means an import, variable or parameter is never read, under noUnusedLocals or noUnusedParameters. Remove it, or prefix a parameter with _.",
      "intro": [
        "`error TS6133: 'count' is declared but its value is never read.` is reported, with `noUnusedLocals` on, for imports, variables, functions and private class members that nothing reads, and with `noUnusedParameters` on, for parameters. Neither option is part of `strict`.",
        "With both options off the checker still notices: editors that run TypeScript's language service show the same names faded out, as a suggestion rather than an error, and `tsc` prints nothing."
      ],
      "cause": [
        "Code was removed and its import or variable was left behind.",
        "A parameter is required by a callback's position but not used (`(event, index) => ...` using only `index`).",
        "`noUnusedLocals` or `noUnusedParameters` is on."
      ],
      "examples": [
        "errors/ts6133-unused"
      ],
      "fixes": [
        {
          "id": "remove-or-underscore",
          "heading": "Remove it, or start a parameter's name with _",
          "body": [
            "Delete unused imports and variables. A parameter you must keep for its position can start with an underscore (`_currency`), which `noUnusedParameters` skips by design."
          ],
          "examples": [
            "errors/ts6133-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "An import used only in a JSDoc type counts as read. For imports that exist only for types, `@import` is cleaner: it is a comment, so it adds no import to the running code.",
        "Destructuring to drop a property (`const { password, ...user } = row`) is not reported: unused names next to a rest element are ignored, so this way of removing a property stays clean under `noUnusedLocals`."
      ],
      "related": [
        "config/no-unused-locals",
        "tags/import",
        "config/strict",
        "errors/ts2578",
        "editors/vs-code"
      ],
      "sources": [
        {
          "title": "TSConfig Reference: noUnusedLocals",
          "url": "https://www.typescriptlang.org/tsconfig/#noUnusedLocals",
          "publisher": "TypeScript"
        },
        {
          "title": "TSConfig Reference: noUnusedParameters",
          "url": "https://www.typescriptlang.org/tsconfig/#noUnusedParameters",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts17004",
      "slug": "ts17004",
      "code": 17004,
      "title": "TS17004: JSX without a jsx setting",
      "message": "Cannot use JSX unless the '--jsx' flag is provided.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [
        {
          "option": "jsx",
          "effect": "off"
        }
      ],
      "summary": "TS17004 means a .jsx file (or JSX in a .js file) is checked with no jsx option. Set jsx to preserve or react-jsx to match what your bundler does.",
      "intro": [
        "`error TS17004: Cannot use JSX unless the '--jsx' flag is provided.` is reported on each JSX element when the config has no `jsx` setting. The checker can read JSX, but only once it is told how the JSX will be turned into JavaScript.",
        "For a JavaScript project with a bundler, the bundler does that work, so the usual value is `\"preserve\"`, which checks the JSX and leaves it alone, or `\"react-jsx\"` for React's automatic runtime. When no JSX types are loaded either, each element is also reported as [TS7026](/errors/ts7026/)."
      ],
      "cause": [
        "`jsx` is not set in `jsconfig.json`.",
        "The file has JSX (`.jsx`, or JSX in a `.js` file)."
      ],
      "examples": [
        "errors/ts17004-no-jsx"
      ],
      "fixes": [
        {
          "id": "set-jsx",
          "heading": "Set jsx",
          "body": [
            "Add `\"jsx\": \"preserve\"` (the bundler transforms JSX) or `\"react-jsx\"` (React's automatic runtime; it needs React's types installed). The [jsx page](/config/jsx/) lists the values and what each one expects."
          ],
          "examples": [
            "errors/ts17004-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "With `react-jsx` and no React types, the checker reports that `react/jsx-runtime` cannot be found (TS2875), which means installing `@types/react` (or the framework's own types).",
        "`include` must match `.jsx` files; `[\"src/**/*.js\"]` leaves them unchecked."
      ],
      "related": [
        "config/jsx",
        "errors/ts7026",
        "config/include"
      ],
      "sources": [
        {
          "title": "JSX",
          "url": "https://www.typescriptlang.org/docs/handbook/jsx.html",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: jsx",
          "url": "https://www.typescriptlang.org/tsconfig/#jsx",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts7026",
      "slug": "ts7026",
      "code": 7026,
      "title": "TS7026: JSX elements without JSX types",
      "message": "JSX element implicitly has type 'any' because no interface 'JSX.{0}' exists.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [
        {
          "option": "noImplicitAny",
          "effect": "on"
        },
        {
          "option": "strict",
          "effect": "on"
        }
      ],
      "summary": "TS7026 means JSX is checked but no JSX types are loaded, so every element is any. Install your framework's types, or declare JSX.IntrinsicElements.",
      "intro": [
        "`error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.` is reported for JSX elements when the checker has no `JSX` namespace telling it which elements and attributes exist. Under `noImplicitAny` the resulting `any` is an error, reported on each opening and closing tag.",
        "The `JSX` types come from the framework: React's (`@types/react`), Preact's, Solid's. They are missing when the package is not installed, or when a `types` list or `jsxImportSource` points somewhere else."
      ],
      "cause": [
        "`jsx` is set, but no package that declares the `JSX` namespace is loaded.",
        "`noImplicitAny` is on (part of `strict`)."
      ],
      "examples": [
        "errors/ts7026-no-jsx-types"
      ],
      "fixes": [
        {
          "id": "framework-types",
          "heading": "Load the framework's JSX types",
          "body": [
            "Install the types your JSX runtime publishes, and for an automatic runtime set `jsxImportSource` to the framework. For a project with its own small JSX runtime, declare the namespace yourself in a `.d.ts` file, as the fixed example does with a catch-all `IntrinsicElements`."
          ],
          "examples": [
            "errors/ts7026-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "A catch-all `IntrinsicElements` accepts any element and attribute, so typos in tag names pass; real framework types check them.",
        "Without any `jsx` setting the elements are also [TS17004](/errors/ts17004/)."
      ],
      "related": [
        "config/jsx",
        "errors/ts17004",
        "config/types",
        "config/no-implicit-any"
      ],
      "sources": [
        {
          "title": "JSX: Intrinsic elements",
          "url": "https://www.typescriptlang.org/docs/handbook/jsx.html#intrinsic-elements",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "TSConfig Reference: jsxImportSource",
          "url": "https://www.typescriptlang.org/tsconfig/#jsxImportSource",
          "publisher": "TypeScript"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-20"
    },
    {
      "id": "ts2416",
      "slug": "ts2416",
      "code": 2416,
      "title": "TS2416: A subclass member that does not fit the base class",
      "message": "Property '{0}' in type '{1}' is not assignable to the same property in base type '{2}'.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2416 means a subclass overrides a method or property with a type the base class's version does not allow. Keep the override compatible with the base.",
      "intro": [
        "A subclass can be used anywhere its base class is expected, so each member it overrides has to fit the base member's type: a method returning a `number` cannot be overridden by one returning a string. TS2416 names the member and both types, and the lines under it say what differs.",
        "In a `.js` file the subclass's types come from its JSDoc and from inference, so an override with no annotations is checked against the base class through what its body returns."
      ],
      "cause": [
        "An override returns a different type, as in the example.",
        "An override takes a narrower parameter type than the base method accepts.",
        "A class claims to implement an interface with [`@implements`](/tags/implements/) and a method's parameter type does not fit."
      ],
      "examples": [
        "errors/ts2416-override-type"
      ],
      "fixes": [
        {
          "id": "compatible",
          "heading": "Make the override compatible",
          "body": [
            "Return the base type (here a number) and put the formatting in a new method. If the base class's type is what is wrong, change it there."
          ],
          "examples": [
            "errors/ts2416-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Parameters are compared both ways for methods written as methods (TypeScript's method bivariance), so a narrower parameter in a method override is often accepted; property-style function types are checked strictly under `strictFunctionTypes`."
      ],
      "related": [
        "tags/override",
        "tags/extends",
        "recipes/subclasses-and-overrides",
        "errors/ts2420",
        "recipes/implements-an-interface"
      ],
      "sources": [
        {
          "title": "Classes: overriding methods",
          "url": "https://www.typescriptlang.org/docs/handbook/2/classes.html#overriding-methods",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts2420",
      "slug": "ts2420",
      "code": 2420,
      "title": "TS2420: A class that does not match its @implements type",
      "message": "Class '{0}' incorrectly implements interface '{1}'.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS2420 means a class tagged @implements is missing a member of that type, or one does not fit. Add the member, or fix its type.",
      "intro": [
        "The [`@implements`](/tags/implements/) tag asks TypeScript to check a class against a type: every member the type requires must exist on the class with a compatible type. TS2420 reports the class, and the lines under it name the missing or mismatched member.",
        "It is the JSDoc form of `class MemoryStore implements Store` in a `.ts` file, and it is reported on the class even when nothing else uses it as a `Store` yet, which is the point of the tag."
      ],
      "cause": [
        "A method of the type is missing from the class.",
        "A member exists with an incompatible type (then [TS2416](/errors/ts2416/) may appear on the member too)."
      ],
      "examples": [
        "errors/ts2420-missing-method"
      ],
      "fixes": [
        {
          "id": "add",
          "heading": "Add the missing member",
          "body": [
            "Implement every member the type lists, with compatible types."
          ],
          "examples": [
            "errors/ts2420-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "`@implements` checks the class but does not type its methods' parameters: each still needs its own `@param` (TS7006 otherwise), as the [recipe](/recipes/implements-an-interface/) shows."
      ],
      "related": [
        "tags/implements",
        "recipes/implements-an-interface",
        "errors/ts2416",
        "errors/ts2741"
      ],
      "sources": [
        {
          "title": "JSDoc Reference: @implements",
          "url": "https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#implements",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    },
    {
      "id": "ts18013",
      "slug": "ts18013",
      "code": 18013,
      "title": "TS18013: A #private field read from outside its class",
      "message": "Property '{0}' is not accessible outside class '{1}' because it has a private identifier.",
      "category": "Classes, JSX and unused code",
      "tsCategory": "error",
      "flags": [],
      "summary": "TS18013 means code outside a class reads a #private field. JavaScript itself forbids it; expose what callers need through a method or getter.",
      "intro": [
        "A field whose name starts with `#` is private in JavaScript itself: code outside the class body cannot even name it, and engines reject such code when they parse it. TypeScript reports the same mistake as TS18013 before the code runs.",
        "Unlike [`@private`](/tags/private/), which only TypeScript enforces ([TS2341](/errors/ts2341/)), a `#` field stays private at run time too."
      ],
      "cause": [
        "Reading or writing `object.#field` outside the class that declares it, often in a test or a helper."
      ],
      "examples": [
        "errors/ts18013-private-field"
      ],
      "fixes": [
        {
          "id": "getter",
          "heading": "Expose what callers need",
          "body": [
            "Add a getter or a method on the class, as the fixed example does with `balance`, and keep the field itself private."
          ],
          "examples": [
            "errors/ts18013-fixed"
          ]
        }
      ],
      "sections": [],
      "gotchas": [
        "Code inside the class can read the field on any instance of it, not only `this`, which is how methods such as `equals(other)` work."
      ],
      "related": [
        "recipes/private-fields",
        "tags/private",
        "errors/ts2341",
        "recipes/class-fields-and-constructors"
      ],
      "sources": [
        {
          "title": "Classes: private members",
          "url": "https://www.typescriptlang.org/docs/handbook/2/classes.html#caveats",
          "publisher": "TypeScript handbook"
        },
        {
          "title": "Private properties",
          "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties",
          "publisher": "MDN Web Docs"
        },
        {
          "title": "diagnosticMessages.json (TypeScript 5.9.3)",
          "url": "https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/diagnosticMessages.json",
          "publisher": "TypeScript on GitHub"
        }
      ],
      "updated": "2026-10-21"
    }
  ]
}
