TypeScript error

TS2722: Calling an optional function without a check

  • Error TS2722
  • Reported with strictNullChecks
  • Reported with strict
  • Tested with TypeScript 5.9

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.

At a glance

CodeTS2722
MessageCannot invoke an object which is possibly 'undefined'.
TypeScript's categoryerror
Listed underNull, undefined and unknown
Turned on by strictNullChecks, strict
In .js files Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file

The message is TypeScript's own text from its diagnostic messages file (Apache-2.0).

What it looks like

upload.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: upload.js(7,3): error TS2722: Cannot invoke an object which is possibly 'undefined'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. upload.js(7,3): error TS2722: Cannot invoke an object which is possibly 'undefined'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. upload.js(7,3): error TS2722: Cannot invoke an object which is possibly 'undefined'. checked 21 October 2026
/**
 * @param {File} file
 * @param {{ onProgress?: (percent: number) => void }} [options]
 */
export function upload(file, options = {}) {
  options.onProgress(0);error TS2722: Cannot invoke an object which is possibly 'undefined'.
  return file.name;
}
Calling an optional callback.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What causes it

  • A property declared with ? (or a parameter marked optional) holds a function, and the code calls it directly.
  • strictNullChecks (part of strict) is on.

How to fix it

Call it with ?.()

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.

upload.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
/**
 * @param {File} file
 * @param {{ onProgress?: (percent: number) => void }} [options]
 */
export function upload(file, options = {}) {
  options.onProgress?.(0);
  return file.name;
}

/**
 * @param {File} file
 * @param {{ onProgress?: (percent: number) => void }} [options]
 */
export function uploadQuietly(file, { onProgress = () => {} } = {}) {
  onProgress(0);
  return file.name;
}
Call it with ?.(), or give it a default.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

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.

Sources

Last reviewed 20 October 2026.