TypeScript Version Notes (5.5 → 7.x)
Only the changes that alter advice, not the full release notes. Check the project's installed version before applying anything here — npx tsc --version, or read typescript in package.json.
Contents
- Check the version first
- TypeScript 7.0 — the native compiler
- TypeScript 6.0 — the deprecation cutover
- 5.9 — inference tightening,
import defer,--module node20 - 5.8 —
erasableSyntaxOnly - 5.7 — uninitialized variable checks
- 5.6 — iterator and truthiness checks
- 5.5 — inferred type predicates
- Advice that aged out
Check the version first
npx tsc --version
Most of the guidance in this skill is version-independent, but the items below are not. Recommending erasableSyntaxOnly to a project on 5.4 wastes everyone's time, and hand-writing a type predicate on 5.9 adds noise.
TypeScript 7.0 — the native compiler
7.0 replaced the JavaScript compiler with a native (Go) port. What actually matters day to day:
tscis still the command. Thetypescriptpackage exposesbin/tscas before, sotsc --noEmitremains the right way to reproduce an error. There is no separatetsgobinary to invoke in a released 7.x — that name belonged to the@typescript/native-previewpackage during the preview period.- Type-checking semantics match 6.0 with
--stableTypeOrderingon and noignoreDeprecationsset. Every 6.0 default change and deprecation (below) is a hard error in 7.0. Treat any other behavioural difference as a bug worth reporting upstream, not as something to design around. - Speed changes workflow. Full-project checks are cheap enough that "run
tsc --noEmitand read the real error" beats reasoning from a snippet, even on large repos. Lean on it harder than you would have on 5.x. - No programmatic compiler API in 7.0.
import ts from "typescript"has nothing to import until 7.1 ships a new API. Tools that need one (typescript-eslint, ts-morph, custom transformers, Volar-based editor tooling for Vue/Svelte/Astro/MDX, Angular template checking) stay on 6.x via the bridge package@typescript/typescript6, which re-exports the 6.0 API and ships atsc6binary. The documented layout aliases it in astypescriptand installs 7.0 under another name sonpx tscis native and the tooling keeps its API. For type-design work this means: check with 7.0'stsc, but expect the editor in a Vue/Svelte/Astro project to still be reporting 6.x diagnostics. - Template literal inference splits on Unicode code points. With
type HeadTail<S> = S extends`${infer Head}${infer Tail}`? [Head, Tail] : never,HeadTail<"😀abc">is now["😀", "abc"]; through 6.x it was["\ud83d", "\ude00abc"]. RecursiveLength/Reverse/Splitutilities change their answers for non-BMP input — see template-literal-types.md. - JS files are checked like TS files. Closure-style JSDoc (
@enum,@class, bare?, postfix!,function(string): void) is no longer specially recognized — relevant when migrating JavaScript toward types.
TypeScript 6.0 — the deprecation cutover
6.0 is the final JavaScript-based release and exists mainly to remove long-deprecated options and align behaviour with 7.0. If a project is on 6.x and something stopped compiling after the upgrade, suspect a default change or removed tsconfig option before suspecting a type bug.
- Defaults flipped:
strict: true,module: "esnext",targetfloats to the latest stable ES version (es2025at release),types: [](only listed@typespackages become globals;["*"]restores the old sweep), androotDiris thetsconfig.jsondirectory instead of the inferred common source root. The two symptoms to recognize: a sudden wave of strict-mode errors in a project that never setstrict, andCannot find name 'describe'/processbecause@types/*are no longer auto-included. - Removed with no-op behaviour under
ignoreDeprecations: "6.0", hard errors in 7.0:target: es5,downlevelIteration,moduleResolution: node/node10/classic,module: amd/umd/systemjs/none,baseUrl,outFile,esModuleInterop: false,alwaysStrict: false,modulekeyword for namespaces,asserton imports (usewith). --stableTypeOrderingmakes 6.0 sort types and symbols the way 7.0's parallel checker does. Union order in declaration emit and error text stops depending on declaration order, and an error that appears only under the flag is an inference that happened to work by luck — fix it with an explicit type argument (call<Explicit>(…)) or a variable annotation. Diagnostic aid only (up to 25% slower); it is always on and unconfigurable in 7.0.- Less context-sensitivity for
this-less functions. A function whose parameters lack annotations used to be skipped during type-argument inference whenever it could referencethis(method syntax,functionexpressions). 6.0 only treats it as context-sensitive if the body actually usesthis, socallIt({ consume(y) { … }, produce(x: number) { … } })now infersyregardless of property order. Expect fewer'y' is of type 'unknown'errors on upgrade, and a few generic calls (notably generic JSX) that now need an explicit type argument.
5.9 — inference tightening, import defer, --module node20
- Type-argument inference no longer leaks type variables (microsoft/TypeScript#61668). Some calls that inferred a leaked
Tnow report errors or produce a different type. The fix is almost always an explicit type argument on the generic call; recommend that before restructuring the types. import defer * as ns from "./mod"defers module evaluation until a member ofnsis first accessed. Namespace form only —import defer { x }andimport defer xare syntax errors — and it is never downleveled, so it needs--module esnextorpreserveand a runtime or bundler that implements it.--module node20is a frozen snapshot of Node 20 resolution (implies--target es2023), unlikenodenext, which keeps moving. Suggest it when a project wants resolution that will not change under its feet.lib.d.ts:ArrayBufferis no longer a supertype of typed arrays, soBuffer/Uint8Arraypassed whereArrayBufferis expected now errors. WriteUint8Array<ArrayBuffer>explicitly, pass.buffer, or update@types/node.
5.8 — erasableSyntaxOnly
--erasableSyntaxOnly rejects TypeScript syntax that emits runtime code, so a file can be stripped rather than compiled (what Node's native TS support and tsx do). It bans:
enumdeclarationsnamespace/moduleblocks with runtime members- constructor parameter properties (
constructor(private x: string) {}) - non-ECMAScript
import x = require(...)/import x = ns.yaliases andexport =assignments
This makes the as const object pattern the default choice over enum rather than merely the recommended one — see as-const-typeof.md. When a project sets this flag, a suggestion built on enum simply won't compile.
5.7 — uninitialized variable checks
TypeScript now reports variables that are never initialized before use in more positions than it used to. When diagnosing "used before assigned" style errors, confirm the target version before assuming the code was always broken. See error-diagnosis.md.
5.6 — iterator and truthiness checks
Two additions that surface as new errors on upgrade:
- Disallowed nullish and truthy checks — expressions that are always truthy or always nullish (a common typo class, e.g.
if (/re/)) are now errors rather than silently-dead branches. - Strict builtin iterator checks — tighter typing on
Iterator/IteratorResulthelpers, which can surface in generic code that hand-rolls iterables.
5.5 — inferred type predicates
The single most advice-changing release for this skill. A function with no explicit return type that returns a narrowing boolean expression gets a value is T predicate inferred automatically:
// TS infers `v is number` — no annotation, no helper needed
const nums = [1, null, 2].filter((v) => v !== null);
Full rules, and the four cases where inference still doesn't apply, are in type-narrowing.md. Note that assertion signatures (asserts value is T) are still never inferred — see assertion-functions.md.
Also in 5.5: control-flow narrowing through constant indexed access, which makes some of the index-access workarounds in array-index-access.md unnecessary.
Advice that aged out
| Old advice | Status |
|---|---|
Always annotate value is T on a guard |
Superseded on 5.5+. Annotate only when inference can't apply |
Write a isNotNull helper to filter nullables |
Optional on 5.5+. Inline callbacks narrow on their own |
Prefer enum for a closed set of values |
Unusable under erasableSyntaxOnly (5.8+). Use as const objects |
F.Narrow / ts-toolbelt for literal preservation |
Superseded since 5.0 by const type parameters — see deep-inference.md |
Invoke the native compiler as tsgo |
Preview-only name. Released 7.x uses tsc |
Count string length at the type level by peeling ${infer H}${infer T} |
Counts UTF-16 code units on ≤6.x, code points on 7.0+ — see template-literal-types.md |
See also
- type-narrowing.md — inferred predicates in full
- as-const-typeof.md — the
enumalternative - error-diagnosis.md — reading compiler output
- deep-inference.md —
consttype parameters