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
| Release | TypeScript 5.6 |
|---|---|
| Released | 9 September 2024, the day of its announcement on the TypeScript blog |
| Source | TypeScript 5.6 release notes |
| Examples | Every example runs through TypeScript 5.9.3 when this site is built. |
| Previous release | TypeScript 5.5 |
| Next release | TypeScript 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.
/** @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);
}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).
/** @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();
}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.
import "./polyfils.js";error TS2307: Cannot find module './polyfils.js' or its corresponding type declarations.
import "./setup.js";
console.log("ready");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 adonecheck (orstrictBuiltinIteratorReturn: false). tsc --buildalways writes a.tsbuildinfofile.- The
"type"field of a package insidenode_modulesis respected under everymodulesetting, 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
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
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.
/** @param {string} message */
export function debug(message) {
if (globalThis.DEBUG) console.log(message);
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js", "*.d.ts"]
} Gotchas
- Destructure both
valueanddonefromnext(), then checkdone; the check narrowsvalueto the element type.
Sources
- TypeScript 5.6 release notes · TypeScript handbook
- Announcing TypeScript 5.6 · TypeScript blog
Last reviewed 20 October 2026.