TypeScript release

TypeScript 5.6 for JavaScript users

  • Released 9 September 2024
  • Examples run with TypeScript 5.9

TypeScript 5.6 was announced on 9 September 2024. It reports conditions that can only go one way, such as a regular expression used as an if condition instead of calling .test(), and under strict it types the value of a finished built-in iterator as undefined, not any.

It added noUncheckedSideEffectImports for misspelled side-effect imports, --noCheck for writing output without checking, and editor changes that report errors for the visible part of a file first.

At a glance

ReleaseTypeScript 5.6
Released9 September 2024, the day of its announcement on the TypeScript blog
SourceTypeScript 5.6 release notes
ExamplesEvery example runs through TypeScript 5.9.3 when this site is built.
Previous releaseTypeScript 5.5
Next releaseTypeScript 5.7

What changed for JavaScript

Conditions that are always truthy or nullish

A condition TypeScript can tell from its syntax is always truthy is an error (TS2872): a regular expression literal without .test(), an arrow function written where >= was meant, an object literal. A ?? whose left side can never be nullish is reported too. true, false, 0 and 1 are allowed, so while (true) stays fine.

hex.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: hex.js(4,7): error TS2872: This kind of expression is always truthy. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. hex.js(4,7): error TS2872: This kind of expression is always truthy. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. hex.js(4,7): error TS2872: This kind of expression is always truthy. checked 21 October 2026
/** @param {string} value */
export function isHexLoose(value) {
  if (/^0x[0-9a-f]+$/i) {error TS2872: This kind of expression is always truthy.
    return true;
  }
  return false;
}

/** @param {string} value */
export function isHex(value) {
  return /^0x[0-9a-f]+$/i.test(value);
}
A regular expression used as a condition is always truthy.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": [
    "*.js"
  ]
}

Built-in iterators under strict

The value of an iterator result before you check done used to be any for built-in iterators. A new option in the strict family, strictBuiltinIteratorReturn, makes it undefined, so map.keys().next().value is string | undefined and has to be checked (TS18048).

first.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: first.js(5,10): error TS18048: 'value' is possibly 'undefined'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. first.js(5,10): error TS18048: 'value' is possibly 'undefined'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. first.js(5,10): error TS18048: 'value' is possibly 'undefined'. checked 21 October 2026
/** @param {Map<string, number>} counts */
export function firstKeyLoose(counts) {
  const { value } = counts.keys().next();
  return value.toUpperCase();error TS18048: 'value' is possibly 'undefined'.
}

/** @param {Map<string, number>} counts */
export function firstKey(counts) {
  const { value, done } = counts.keys().next();
  return done ? "" : value.toUpperCase();
}
Under strict, next() on a built-in iterator may give undefined.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": [
    "*.js"
  ]
}

noUncheckedSideEffectImports

An import with no bindings, import "./polyfills.js", was never resolved, so a misspelled path passed. With the new option on, it has to resolve. TypeScript 6.0 turns it on by default.

main.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: main.js(2,8): error TS2307: Cannot find module './polyfils.js' or its corresponding type declarations. 6.0.3 : differs, see why TypeScript 6.0.3, run 21 October 2026: differs from 5.9.3. main.js(2,8): error TS2882: Cannot find module or type declarations for side-effect import of './polyfils.js'. 7.0.2 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. main.js(2,8): error TS2882: Cannot find module or type declarations for side-effect import of './polyfils.js'. setup.js(1,12): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. checked 21 October 2026
import "./polyfils.js";error TS2307: Cannot find module './polyfils.js' or its corresponding type declarations.
import "./setup.js";

console.log("ready");
noUncheckedSideEffectImports on: a misspelled side-effect import.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": [],
    "noUncheckedSideEffectImports": true
  },
  "include": [
    "*.js"
  ]
}

--noCheck

--noCheck writes output without type-checking. For a JavaScript library that writes .d.ts files from its JSDoc, it separates the two jobs: write declarations with --noCheck, and check with tsc -p jsconfig.json as usual.

Errors for the visible part of the file first

Editors can ask for the errors in the region on screen before the whole file, which the release notes show cutting the first response in a very large file from seconds to well under a second.

What did not change

Iterator helper methods (map, filter, take on iterators) were added to the esnext lib in this release; a project that targets an older lib does not see them.

Upgrade notes

From the behavioral changes:

  • New TS2872 and related errors for conditions that cannot change.
  • Under strict, iterator results need a done check (or strictBuiltinIteratorReturn: false).
  • tsc --build always writes a .tsbuildinfo file.
  • The "type" field of a package inside node_modules is respected under every module setting, which can change how a dependency's types are read.

Under TypeScript 6.0 and 7.0

Every example on this page also runs under TypeScript 6.0.3 and 7.0.2 when this site is built. One of them reports something different from 5.9.3, the version the page describes; the ✗ on its badge links to its entry below.

An unresolved side-effect import has its own code

TypeScript 6.0 and 7.0 · other checker changes

The pattern: A side-effect import of a missing file with noUncheckedSideEffectImports on.

Why: 5.9 reports it as TS2307 ("Cannot find module"); TypeScript 6.0.3 and 7.0.2 report TS2882 ("Cannot find module or type declarations for side-effect import") on the same line. The release notes do not list the new code. Code that is right is unaffected; a script that filters tsc's output for TS2307 needs both codes. Source: TypeScript 6.0 release notes: Simple default changes.

noUncheckedSideEffectImports on: a misspelled side-effect import main.js

TypeScript 5.9.3
main.js(2,8): error TS2307: Cannot find module './polyfils.js' or its corresponding type declarations.
TypeScript 6.0.3differs from 5.9.3
main.js(2,8): error TS2882: Cannot find module or type declarations for side-effect import of './polyfils.js'.
TypeScript 7.0.2differs from 5.9.3
main.js(2,8): error TS2882: Cannot find module or type declarations for side-effect import of './polyfils.js'.
setup.js(1,12): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.

What works in every version: Nothing to rewrite: the same broken import, reported under a new code.

Assigning to globalThis does not declare a global

TypeScript 7.0 · JSDoc and JavaScript patterns 7.0 no longer reads

The pattern: globalThis.appReady = true; in a .js file, with nothing declaring appReady.

Why: 5.9 read the assignment as a declaration of the global, as it reads other expando assignments in .js files. TypeScript 7.0.2 does not, so under strict the assignment is TS7017. The port's list of changes narrows expando declarations without naming globalThis. Source: CHANGES.md: Expando declarations.

noUncheckedSideEffectImports on: a misspelled side-effect import main.js

TypeScript 5.9.3
main.js(2,8): error TS2307: Cannot find module './polyfils.js' or its corresponding type declarations.
TypeScript 6.0.3differs from 5.9.3
main.js(2,8): error TS2882: Cannot find module or type declarations for side-effect import of './polyfils.js'.
TypeScript 7.0.2differs from 5.9.3
main.js(2,8): error TS2882: Cannot find module or type declarations for side-effect import of './polyfils.js'.
setup.js(1,12): error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.

What works in every version: Declare the global with var in a .d.ts file.

debug.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 {string} message */
export function debug(message) {
  if (globalThis.DEBUG) console.log(message);
}
Declare the global with var in a .d.ts file.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js", "*.d.ts"]
}

Gotchas

  • Destructure both value and done from next(), then check done; the check narrows value to the element type.

Sources

Last reviewed 20 October 2026.