← Back to blog

TypeScript 7.0: What’s New and What Breaks

9 min read

TypeScript just went through its biggest architectural shift since the project began. Back in August, I wrote about TypeScript 5.9 and its leaner configs and deferred imports. Since then, the team also shipped TypeScript 6.0 - a release I didn't get around to covering here, but one that turns out to matter a lot in retrospect - and then TypeScript 7.0, a complete native port of the compiler written in Go. If you've been sitting on 5.9, this is not a routine minor-version bump you can skim past. Here's what actually changed, what's safe to ignore, and what will break your build.

TL;DR

TypeScript 5.9 (Aug 2025) is the last "classic" TypeScript most people know well. TypeScript 6.0 (Mar 2026) was the final release built on the original JavaScript codebase - a deliberate transition and cleanup version. TypeScript 7.0 (Jul 2026) is a full rewrite of the compiler in Go, with the same behavior but a radically faster runtime.

The team's own framing is useful here: 6.0 exists specifically to absorb the breaking changes before the engine swap, so that 7.0 itself is "just" a performance release on top of already-adjusted code. If you're upgrading straight from 5.9 to 7.0, you're getting both sets of changes at once.

The Headline Feature: A Native Compiler

TypeScript 7.0 is not incrementally faster - it's a different implementation entirely. The compiler and language service were rewritten in Go, trading the old single-threaded JavaScript engine for native code with real multithreading. In the team's own benchmarks on large open-source codebases, build times on vscode dropped from 125.7s to 10.6s (about 12x faster), sentry went from 139.8s to 15.7s (roughly 9x), and both bluesky and playwright saw builds run about 8.7x faster.

Memory usage dropped too (roughly 6–26% depending on the project), and editor responsiveness improved even more dramatically - opening a file and seeing the first error in the VS Code repo went from ~17.5 seconds to under 1.3 seconds.

Two new flags let you tune this:

  • --checkers N - number of parallel type-checking workers (default 4). More cores, more speed, more memory.
  • --builders N - number of project references built in parallel under --build, useful for monorepos.
  • --singleThreaded - disables parallelism entirely, handy for debugging or constrained CI environments.

What to watch for: varying --checkers can occasionally surface order-dependent type results in edge cases. If reproducibility across machines matters to your team, pin the value in CI.

--watch mode was also rebuilt from scratch on a Go port of Parcel's file watcher, replacing the old polling-based approach. It should be noticeably lighter on large node_modules trees.

Defaults That Changed (and Will Break Silent Assumptions)

This is the part most people miss. TypeScript 7.0 doesn't just adopt 6.0's new defaults - it hard-enforces them with no escape hatch:

  • strict now defaults to true instead of false.
  • module now defaults to esnext regardless of target, instead of varying by target.
  • target now defaults to the latest stable ECMAScript version before esnext, instead of an older fixed version.
  • types now defaults to an empty list - ambient @types/* packages are no longer auto-included and must be listed explicitly.
  • rootDir now defaults to ./ and must be set explicitly if tsconfig.json isn't sitting right next to your source folder - it used to be inferred.
  • noUncheckedSideEffectImports now defaults to true.
  • stableTypeOrdering is now always on and can't be turned off.

The types and rootDir changes are the ones that quietly break the most projects. If your tsconfig.json sits at the repo root but your source lives in src/, you now need:

  {
      "compilerOptions": {
+         "rootDir": "./src"
      },
      "include": ["./src"]
  }

And if you were relying on ambient @types packages being picked up automatically:

  {
      "compilerOptions": {
+         "types": ["node", "jest"]
      }
  }

Options That Are Just Gone

These aren't deprecated with a warning anymore - in 7.0 they're hard errors:

  • target: es5 and downlevelIteration
  • moduleResolution: node / node10 / classic => use nodenext or bundler
  • module: amd, umd, systemjs, none => use esnext or preserve
  • baseUrl => rewrite paths relative to the project root instead
  • esModuleInterop: false and alwaysStrict: false are no longer settable
  • The module keyword can't be used where namespace is expected
  • asserts on imports is gone in favor of the with keyword (aligning with the import attributes proposal)

If you're currently on 5.9, running the upgrade to 6.0 first with "ignoreDeprecations": "6.0" set will surface all of these as warnings before they become hard failures in 7.0 - genuinely worth doing rather than jumping straight to 7.0 cold.

Smaller Language and Type-System Changes

Not everything is about the compiler internals. A few changes affect how you write types day to day:

  • Template literal types now respect Unicode code points. Previously, inferring over a string containing an emoji split it into UTF-16 surrogate halves. In 7.0, HeadTail<"😀abc"> infers ["😀", "abc"] instead of splitting the emoji in two. This is a breaking change if you built string-length utilities that depended on the old UTF-16 behavior.
  • RegExp.escape, new Temporal API types, and es2025 as a valid target/lib value all landed in 6.0.
  • #/-prefixed subpath imports are now recognized.
  • The dom lib now bundles dom.iterable and dom.asynciterable rather than requiring them separately.
  • Method-syntax functions that don't reference this now participate in inference slightly earlier, which can (rarely) change inferred types in generic-heavy code.

JavaScript/JSDoc Support Got Stricter

If you type-check plain .js files with JSDoc, this is the section to read carefully. TypeScript 7.0 reworked JS analysis to align more closely with how .ts files are checked, dropping several Closure-flavored conveniences:

  • Values can't stand in for types - use typeof someValue instead.
  • @enum is no longer special-cased.
  • A bare ? is no longer valid as a type; use any.
  • @class no longer makes a function a constructor - use an actual class.
  • Postfix ! isn't supported in JSDoc types.
  • Closure-style function signatures like function(string): void must become (s: string) => void.

What's Not Ready Yet

Worth knowing before you flip the switch project-wide: TypeScript 7.0 ships without a public compiler API. Tools that embed the TypeScript compiler programmatically - typescript-eslint, bundler plugins, and language tooling for Vue, Svelte, Astro, and Angular - can't run on 7.0 yet. The team publishes a compatibility package, @typescript/typescript6, with a tsc6 binary so you can alias your way to running both side by side:

{
  "devDependencies": {
    "@typescript/native": "npm:typescript@^7.0.2",
    "typescript": "npm:@typescript/typescript6@^6.0.2"
  }
}

A new API is expected in 7.1. Until then, projects using framework tooling that embeds TypeScript should keep the editor on 6.0 while using 7.0's tsc for fast CLI type-checking.

Should You Actually Upgrade to 7.0?

There's no universal "yes, do it now" here - it depends on your situation.

It's worth moving to 7.0 if slow builds are a real pain point for your team, whether in CI or local development - an 8–12x speedup is noticeable on any mid-to-large project. It also makes sense if you don't have a hard dependency on tools that hook into the compiler's programmatic API, and if you're willing to spend real time on the migration itself - this isn't a one-click update, since things like rootDir, types, and moduleResolution genuinely break.

On the other hand, it's reasonable to wait if your project relies on Vue, Svelte, Astro, or Angular - their language tooling can't run on TS 7.0 yet, since there's no public compiler API. You'd end up keeping the editor on 6.0 and using 7.0 only for CLI type-checking, which adds setup complexity for little day-to-day benefit. The same goes if you lean heavily on typescript-eslint or other tools that embed the compiler directly - they're waiting on the same API, expected in 7.1. It's also fine to hold off if your project is small enough that build times were never an issue, since the speed gains simply won't be felt in daily work, or if you don't have the bandwidth right now to work through the breaking changes - especially if you're still on 5.9, where jumping straight to 7.0 means absorbing both the 6.0 and 7.0 changes at once.

If you do decide to upgrade, don't jump straight to 7.0. Update to 6.0 first with "ignoreDeprecations": "6.0" set, work through the warnings it surfaces, and only then move to 7.0 - that way the breaking changes land in two manageable batches instead of one big one.

If build speed isn't currently causing you pain, delaying the upgrade costs you nothing - the surrounding ecosystem (types, tooling, framework support) is still visibly catching up to 7.x.

Migration Checklist

  1. Upgrade to 6.0 first, even briefly, and turn on "ignoreDeprecations": "6.0" to see every warning without breaking the build immediately.
  2. Fix rootDir and types in tsconfig.json - these are the two most common silent breaks.
  3. Search for moduleResolution: node, classic, baseUrl, and target: es5 in your configs.
  4. If you rely on tools with deep compiler integration (ESLint, Vue/Svelte/Astro tooling), plan to stay on @typescript/typescript6 for those specific tools.
  5. Re-run your test suite with strict: true - this alone can surface a meaningful number of new errors in older codebases.
  6. Once on 7.0, experiment with --checkers and --builders for your CI machine's core count before assuming the defaults are optimal.

Further Reading

Conclusion

TypeScript 6.0 and 7.0 aren't feature releases in the usual sense - they're a coordinated migration off a decade-old codebase onto a faster foundation, with 6.0 doing the cleanup and 7.0 delivering the payoff. The type system itself hasn't fundamentally changed; what changed is stricter defaults, a handful of removed legacy options, and a compiler that's an order of magnitude faster. If your project already compiles cleanly on 6.0 with no ignoreDeprecations flag set, moving to 7.0 should be close to a no-op - just faster.