TypeScript release

TypeScript 5.8 for JavaScript users

  • Released 28 February 2025
  • Examples run with TypeScript 5.9

TypeScript 5.8 was announced on 28 February 2025. In checked JavaScript the change most people meet is a stricter return check: each branch of a conditional in a return statement is compared with the declared @returns type, so an any in one branch no longer hides a wrong value in the other.

For Node.js projects it follows Node.js 22: a CommonJS file may require() an ES module under module: nodenext, a new stable module: node18 keeps the older rules, and the old assert import syntax is an error under nodenext.

At a glance

ReleaseTypeScript 5.8
Released28 February 2025, the day of its announcement on the TypeScript blog
SourceTypeScript 5.8 release notes
ExamplesEvery example runs through TypeScript 5.9.3 when this site is built.
Previous releaseTypeScript 5.7
Next releaseTypeScript 5.9

What changed for JavaScript

Each branch of a returned conditional is checked

In return cache.has(href) ? cache.get(href) : href, the first branch is any (cache is a Map<string, any>), and before 5.8 the whole conditional became any, so returning a string from a function declared @returns {Link} passed. Now each branch is checked against the return type on its own (TS2322 on href).

links.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: links.js(17,46): error TS2322: Type 'string' is not assignable to type 'Link'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. links.js(17,46): error TS2322: Type 'string' is not assignable to type 'Link'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. links.js(17,46): error TS2322: Type 'string' is not assignable to type 'Link'. checked 21 October 2026
class Link {
  /** @param {string} href */
  constructor(href) {
    this.href = href;
  }
}

/** @type {Map<string, any>} */
const cache = new Map();

/**
 * @param {string} href
 * @returns {Link}
 */
export function toLink(href) {
  return cache.has(href) ? cache.get(href) : href;error TS2322: Type 'string' is not assignable to type 'Link'.
}
Each branch of a returned conditional is checked against @returns.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": [
    "*.js"
  ]
}

require() of an ES module under nodenext

Node.js 22 lets CommonJS code require() an ES module (one without top-level await). Under module: nodenext, TypeScript 5.8 accepts it too, so a .cjs file, or a .js file in a package without "type": "module", can require an ESM-only package. This site's tests confirm with TypeScript 5.9 that the same require is TS1479 under node16.

main.cjs 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
const { add } = require("./math.mjs");

console.log(add(1, 2));
A CommonJS file that require()s an ES module, under nodenext.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": [
    "*.cjs",
    "*.mjs"
  ]
}

module node18

A stable setting for projects that stay on Node.js 18: it does not allow require() of ES modules, and it still accepts assert on imports.

assert on imports is an error under nodenext

Import assertions (assert { type: "json" }) were replaced by import attributes (with { type: "json" }), and Node.js 22 no longer accepts assert. Under nodenext, TypeScript 5.8 reports it (TS2880).

server.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: server.js(2,40): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. server.js(2,40): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. server.js(2,40): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'. checked 21 October 2026
import settings from "./settings.json" assert { type: "json" };error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.

export const port = settings.port;
assert on a JSON import, under nodenext.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": [
    "*.js"
  ]
}

libReplacement

TypeScript looks for packages like @typescript/lib-dom to replace its lib files (see 4.5). "libReplacement": false turns the lookup, and the watching of node_modules that comes with it, off. TypeScript 6.0 makes false the default.

What did not change

erasableSyntaxOnly, the other new option, reports TypeScript-only syntax such as enum and parameter properties. JavaScript cannot contain that syntax, so it changes nothing in a .js file.

Upgrade notes

From the release notes:

  • Replace assert with with on imports under nodenext.
  • Expect new TS2322 errors where one branch of a returned conditional was any.
  • The DOM types changed again.

Gotchas

  • Under nodenext, a JSON import from an ES module also needs with { type: "json" } (TS1543, since 5.7).

Sources

Last reviewed 20 October 2026.