jsconfig.json option

exactOptionalPropertyTypes

  • Default false
  • Since TypeScript 4.4

An optional property, @property {string} [nickname] in JSDoc, normally accepts undefined as a value as well as being left out. exactOptionalPropertyTypes makes it mean only "may be left out": writing nickname: undefined becomes an error (TS2375) unless the type says string | undefined.

The difference is visible at run time: "nickname" in user and Object.keys(user) see a property set to undefined but not a missing one. The option arrived with TypeScript 4.4, is not part of strict, and needs strictNullChecks.

At a glance

Write "exactOptionalPropertyTypes": true if your code tells "missing" from "set to undefined" (with in or Object.keys); otherwise leave it out
On the command line --exactOptionalPropertyTypes
Type boolean
Default in TypeScript 5.9 false
TypeScript's description Interpret optional property types as written, rather than adding 'undefined'.
Generator, relaxed not written
Generator, recommended not written
Generator, strict true

The description is quoted from TypeScript's own option list (Apache-2.0); see the notices. The generator rows are what the jsconfig generator writes at each level.

Examples

main.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: main.js(9,14): error TS2375: Type '{ name: string; nickname: undefined; }' is not assignable to type 'User' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties. Types of property 'nickname' are incompatible. Type 'undefined' is not assignable to type 'string'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. main.js(9,14): error TS2375: Type '{ name: string; nickname: undefined; }' is not assignable to type 'User' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties. Types of property 'nickname' are incompatible. Type 'undefined' is not assignable to type 'string'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. main.js(9,14): error TS2375: Type '{ name: string; nickname: undefined; }' is not assignable to type 'User' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties. Types of property 'nickname' are incompatible. Type 'undefined' is not assignable to type 'string'. checked 21 October 2026
/**
 * @typedef {object} User
 * @property {string} name
 * @property {string} [nickname]
 */

/** @type {User} */
export const user = { name: "Ada", nickname: undefined };error TS2375: Type '{ name: string; nickname: undefined; }' is not assignable to type 'User' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
  Types of property 'nickname' are incompatible.
    Type 'undefined' is not assignable to type 'string'.
exactOptionalPropertyTypes on: an optional property may be missing, not undefined.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": [],
    "exactOptionalPropertyTypes": true
  },
  "include": [
    "*.js"
  ]
}
main.js TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @typedef {object} User
 * @property {string} name
 * @property {string} [nickname]
 */

/** @type {User} */
export const user = { name: "Ada", nickname: undefined };
exactOptionalPropertyTypes off: undefined is accepted.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": [
    "*.js"
  ]
}

When undefined is a real value

Say so in the type: @property {string | undefined} [nickname] accepts both a missing property and one set to undefined. Use it where your code writes undefined on purpose, for example to clear a field.

Gotchas

  • Spreading options objects often writes undefined values ({ ...defaults, nickname: input.nickname }), so turning this on in an existing codebase can report many lines that are harmless in practice.
  • Library types are read with the same rule: passing undefined for an optional property of a library's type becomes an error unless that type includes undefined.

Sources

Last reviewed 20 October 2026.