Type expression

Non-null assertions in JavaScript

  • Importing and casting
  • Tested with TypeScript 5.9

In a .ts file, total!.textContent tells TypeScript that total is not null or undefined. In a .js file the ! operator is TS8013 ("Non-null assertions can only be used in TypeScript files"), and there is no JSDoc tag for it. The handbook also notes that ! inside a JSDoc type, as in {!HTMLElement}, has no meaning.

JavaScript code says the same thing in one of four ways, each shown in the second example: check and throw, skip with ?., call an assertion function, or cast.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
Check and stop if (!total) throw new Error("#total is missing"); total!
Skip when missing document.querySelector("#badge")?.classList.add("on"); document.querySelector("#badge")?.classList.add("on");
Assertion function assert(count, "#count is missing"); const count = document.querySelector("#count")!;
Cast /** @type {HTMLElement} */ (document.querySelector("#note")) document.querySelector("#note") as HTMLElement

Examples

total.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: total.js(4,1): error TS8013: Non-null assertions can only be used in TypeScript files. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. total.js(4,1): error TS8013: Non-null assertions can only be used in TypeScript files. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. total.js(4,1): error TS8013: Non-null assertions can only be used in TypeScript files. checked 21 October 2026
const total = document.querySelector("#total");

total!.textContent = "$39.00";error TS8013: Non-null assertions can only be used in TypeScript files.

export {};
The ! operator is TypeScript syntax.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
total.js total.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @param {unknown} value
 * @param {string} message
 * @returns {asserts value}
 */
function assert(value, message) {
  if (!value) throw new Error(message);
}

// 1. Check and stop: the rest of the code sees a non-null value.
const total = document.querySelector("#total");
if (!total) throw new Error("#total is missing");
total.textContent = "$39.00";

// 2. Optional chaining: do nothing when it is missing.
document.querySelector("#badge")?.classList.add("visible");

// 3. An assertion function.
const count = document.querySelector("#count");
assert(count, "#count is missing");
count.textContent = "2";

// 4. A cast: a claim TypeScript does not check.
const note = /** @type {HTMLElement} */ (document.querySelector("#note"));
note.hidden = false;

export {};
const total = document.querySelector("#total");
total!.textContent = "$39.00";

document.querySelector("#badge")?.classList.add("visible");

const count = document.querySelector("#count")!;
count.textContent = "2";

const note = document.querySelector("#note") as HTMLElement;
note.hidden = false;

export {};
Four ways to say a value is present.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Which one to use

A check that throws is the most honest: it narrows the type and fails with a clear message at the point where the assumption breaks. An assertion function packages the same check for reuse. Optional chaining fits elements that may legitimately be absent.

A cast is the closest to ! and checks just as little: if the element is missing, the code fails later with a less helpful error. Keep casts for cases a check cannot express.

Gotchas

  • {!Type} in JSDoc is read as Type; it does not remove null from the value assigned to it.
  • Optional chaining returns undefined when the value is missing, so its result may need its own check.

Questions

How do I write a non-null assertion in JSDoc?

There is no JSDoc form. Use a check (if (!el) throw …), an assertion function, optional chaining, or a cast to the non-null type.

Sources

Last reviewed 20 October 2026.