Home / Articles / Why TypeScript 7's Go Port Broke Linters and Framework Tooling

This article is published in English.

Why TypeScript 7's Go Port Broke Linters and Framework Tooling

Explains why TypeScript 7's faster Go-based compiler ships with an incompatible API, breaking linters, installs, and Vue/Svelte upgrades across the ecosystem.

3041 words

The compiler shipped. The API it was supposed to ship with did not.

Microsoft released TypeScript 7.0 on 8 July 2026, and the headline practically wrote itself: ten times faster. A compiler moved out of JavaScript and into Go, running across multiple threads, tearing through codebases that used to need two full minutes and now finishing before you could even switch to another window. Nearly every newsletter covering the release led with that same benchmark chart.

Then developers actually ran npm install.

What many of them got was a fast binary sitting on top of a broken toolchain. And the breakage wasn't subtle. Lint runs crashed on a simple property read. Package managers rejected the install outright because of a peer dependency range mismatch. Vue and Svelte projects couldn't upgrade at all. A month later, most of that is still the case, and a fix isn't scheduled for any release that currently has a date attached to it.

This is the part of the story that got buried, and it's the part that actually determines whether you should touch this upgrade right now.

The number everyone quoted

Credit where it's due first, because the performance gains are not just marketing spin. Microsoft published its own benchmark numbers in the release announcement, and they're detailed enough to verify.

The team reports speedups in the range of 8x to 12x on full builds, and memory usage actually dropped instead of climbing, which is the opposite of the usual trade-off you'd expect. Slack told Microsoft that type checking in their CI pipeline went from roughly seven and a half minutes down to a little over one minute, and that their editor experience went from barely usable at their scale to loading within seconds. Canva reported that the time to see the first error in the editor fell from about 58 seconds to under 5.

These are legitimate engineering achievements, the product of a year of sustained work. Nothing that follows takes that away.

This was a port, not a rewrite

Here's the technical detail most coverage glossed over, and it's the detail that explains everything else.

TypeScript 7 is a port, not a from-scratch rewrite. The team translated the existing compiler file by file from TypeScript into Go, deliberately preserving the original structure and logic so that type-checking behavior would stay identical. Anything that compiled cleanly under 6.0 is expected to compile identically under 7.0. That's precisely how Microsoft managed to ship a compiler of this scale without a long tail of behavioral regressions, and it reflects real discipline in how the port was executed.

But a compiler is really two separate products sharing one name. There's the binary you invoke, tsc. And there's the library that other tools pull in as a dependency. Linters, test transformers, AST-based codemods, and template checkers don't shell out to tsc and parse whatever text it prints. Instead, they import TypeScript directly, walk your syntax tree with it, and pull type information straight out of the checker.

The port carried over the first product faithfully. It did not carry over the second one at all.

The compiler itself made the trip intact. The API that every surrounding tool depends on did not make the trip with it.

The line buried near the bottom of the release notes

To be fair to Microsoft, this wasn't concealed. If you read through the 7.0 announcement, about two-thirds of the way down, under a section discussing how to run 7.0 alongside 6.0, there's a sentence that a lot of the ecosystem spent July talking about: TypeScript 7.0 ships without an API.

That's a significant gap. Microsoft says it is building a new API and plans to make it available in version 7.1. According to the team, now that the porting work is done, they're shifting focus back to shipping features.

The stated cadence is a new release every three to four months. If that timeline holds, version 7.1 would land around October. That's the extent of what's currently known — there's no confirmed date yet for when the replacement API itself will actually be ready.

Read the announcement from top to bottom and the pattern becomes clear. First comes a table showing how much faster 7.0 performs. Then come glowing quotes from large companies. Only after that does Microsoft note, almost in passing, that a substantial portion of the tooling ecosystem simply cannot run on this version yet.

That ordering was a deliberate editorial choice, not an attempt to mislead anyone. But it's also why so many teams discovered the API gap from a crash log in their terminal rather than from the announcement post itself.

Issue 12518

The most useful artifact to come out of launch week wasn't a benchmark. It was a bug report.

The day the new compiler became publicly available, someone upgrading a Vite plus React project from 6.0.3 to 7.0.2 filed issue 12518 against typescript-eslint, complete with a reproduction. It documented two separate failures.

The first was that npm ci refused to install at all, since typescript-eslint's package metadata pinned a peer dependency range that 7.0.2 fell outside of. The second, for anyone who forced the install anyway, was that ESLint broke inside typescript-estree while building the program, because the code was reaching for a property on the compiler API that no longer existed in this version.

The maintainers closed the issue. Not because they didn't care, but because there was nothing actionable to do.

Read in isolation that looks dismissive. It isn't. The maintainers of typescript-eslint have no path to fixing this themselves — the piece they'd need to build against hasn't shipped yet. Closing the issue was simply an honest statement of fact: the real work belongs on the TypeScript 7.1 side, not inside the linter. Which means the single most widely used TypeScript tool in the ecosystem is currently powerless to do anything about its own compatibility.

The core ESLint team opened a corresponding issue the following day, confirmed they intend to address it, and are similarly stuck waiting on the same missing piece. The Vue tooling maintainers are in the identical position. Everyone downstream is blocked on the same unreleased dependency.

The blast radius

Any package that imports typescript and calls into its internals is exposed to this. Concretely:

  • typescript-eslint, along with every type-aware lint rule built on it. This fails loudly, either at install time or on the very first run — you won't miss it.
  • ts-jest and any transformer built on internal compiler calls. This fails quietly by comparison, surfacing as confusing transform errors rather than an install failure, which is arguably worse because it looks like a problem with your test configuration rather than a version mismatch.
  • ts-morph and any custom codemods built on it. This is the riskiest category. Deep type introspection can degrade silently, producing subtly incorrect output instead of an obvious crash. Audit carefully before running anything destructive against a codebase.
  • Volar-based template checking, covering Vue, Svelte, Astro, and MDX. Microsoft states directly in the release notes that these workflows likely won't be able to run on TypeScript 7 for now, and advises staying on 6.0 for editor support.
  • Angular's template checking, under the same constraint, with an officially documented workaround: run 7.0 from the command line for fast project-wide error checking, but keep 6.0 in the editor.
  • webpack loaders. Older versions of ts-loader still call the legacy API. One person commenting on the announcement summed up the general mood: eager to upgrade, but with most projects sitting on webpack and no compatible API surface for loaders yet, everyone's waiting on 7.1.

Look closely at what's on that list. None of it is niche or exotic tooling — it's the default toolkit of a typical front-end team working today.

The compiler itself is stable. The ecosystem around it is not. Those are two distinct release states sharing a single version number.

Microsoft's answer: install two compilers at once

Microsoft anticipated this friction and built a workaround rather than leaving teams to improvise one. They published @typescript/typescript6, a compatibility package that ships a tsc6 executable and restores access to the 6.0 API surface. This lets the legacy compiler and the new one coexist without either one stepping on the other's binary name.

The reason this workaround is necessary is that tools such as typescript-eslint resolve TypeScript by package name through a peer dependency. So the recommended fix is to use an npm alias to redirect that name.

The complete dual-compiler setup looks like this:

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

With this in place, your linter, your test transformer, and your codemods keep importing typescript as usual and transparently receive 6.0 under the hood. Meanwhile, running npx tsc resolves to 7.0, so you still get the speed benefit where it matters most — in your editor and in CI.

It works, and credit is due for that: it's a well-designed escape hatch, spelled out in the official announcement rather than something the community had to reverse-engineer.

That said, it's still two separate compiler installations living in one node_modules, resolved through an alias that every new team member will need explained to them, and a configuration you'll eventually have to unwind once 7.1 actually ships. Call it what it is: technical debt with no published due date.

The second trap, for anyone who skipped 6.0

Beyond the missing API, there's a separate cliff waiting for any team that jumped straight from a 5.x release without passing through 6.0 first.

TypeScript 7.0 fully commits to the defaults that 6.0 introduced, and every deprecation warning that 6.0 raised becomes a hard error in 7.0. That lands all at once:

  • strict is now on by default.
  • module now defaults to esnext.
  • rootDir defaults to ./ instead of being inferred, so if your tsconfig.json lives outside src, you now need to set this explicitly or the compiler will misjudge your source layout.
  • types defaults to an empty array rather than pulling in everything. If your code depended on ambient globals coming from installed @types packages, you must either name those packages explicitly or restore the old behavior with ["*"].
  • Several options are removed outright rather than merely discouraged: target: es5, downlevelIteration, moduleResolution: node, baseUrl, plus the amd, umd and systemjs module modes. Using any of them is now a compile error, full stop.

Out of that list, the team singles out rootDir and types as the two changes most likely to catch people off guard, and that matches what you'd expect in practice. Both failure modes flood your terminal with errors that look like the compiler itself is broken, rather than reading as "a default changed under you." That's exactly the kind of confusion that gets filed as a compiler bug instead of fixed with a one-line config edit.

There's also a quieter change aimed at anyone doing type-level string manipulation. Template literal type inference now counts a character such as an emoji as one unit, rather than splitting it into its two UTF-16 code units. That's a more intuitive model for most use cases, but it's a breaking change for any custom Length-style helper type that was intentionally counting UTF-16 code units rather than visible characters.

The practical takeaway: if you're still on a 5.x version, don't leap straight to 7.0. Go through 6.0 first. That intermediate release exists specifically to spread this set of breaking changes across two smaller upgrades instead of dropping all of them on you in a single sitting.

Who this release was actually built for

This is the detail worth sitting with for a moment.

Look at the list of organizations that tested TypeScript 7 ahead of general availability and supplied quotes for the announcement: the VS Code team, Microsoft's own Office, Teams, Power BI, Loop and Xbox groups, plus Bloomberg, Canva, Figma, Google, Linear, Miro, Notion, Sentry, Slack and Vercel. These are codebases running into the millions of lines, backed by dedicated build-infrastructure teams, who ran preview builds for months and fed problems back upstream before launch.

For organizations at that scale, the release genuinely changes how work gets done, and the numbers back that up. Microsoft's own News Services team reports saving 400 hours a month that used to go to waiting on CI. When a single type check used to take seven minutes, cutting that by roughly 8x reshapes an engineer's daily rhythm.

Now compare that to a five-person startup running Nuxt with a type-aware lint setup. Their type check was already down to 9 seconds. The upgrade offers them something like 8 seconds of savings, and in exchange demands a broken lint pipeline, a Vue template checker that simply cannot run, and an alias workaround in package.json that the next engineer to join the team will have to have explained to them.

The speed benefit scales with the size of your codebase. The breakage does not scale at all — it's a fixed cost, applied whether your project has ten files or ten million.

None of this implies bad intent. It's simply what happens when a project optimizes for the feedback it can actually observe. The large enterprise codebases were inside the preview program, so their pain was visible and measurable well before launch. The ecosystem's maintainers — largely volunteers working on linters, IDE integrations, and build tools — were sitting downstream of a decision they had no seat at, and what they got in return was a compatibility shim and a promise that things would be fixed in 7.1.

A huge codebase turns this upgrade into a windfall. A small one just pays the same fixed cost for a much smaller reward. That imbalance is the whole story here.

The readiness check, as of today

A month past general availability, here's roughly where things stand.

If you're considering the move, the lowest-risk path is to run 7.0 as a second, non-blocking type-check job in CI, alongside the one you already have. That gives you real timing numbers and a sense of confidence without making 7.0 the thing your build actually depends on. Once both jobs stay green for about a week, you can flip over.

There's no reward for being an early adopter here, so it's worth knowing the tuning knobs that exist regardless: the --checkers flag controls how many parallel type-checking workers run, defaulting to 4. On a CI runner with limited resources, dropping that to 1 or 2 workers is usually the smarter setting rather than leaving the default in place.

Reproduce the break in about five minutes

None of this needs to be taken on faith, and it shouldn't be — the failure is small and fast enough to trigger deliberately, on a disposable test project, before you touch anything you actually care about.

Start with a fresh Vite React-TypeScript scaffold, add a type-aware ESLint setup, and then try to force the newer compiler into place ahead of it:

npm create vite@latest ts7-probe -- --template react-ts
cd ts7-probe
npm install
npm install -D typescript-eslint eslint
npm install -D typescript@7

Most people hit the wall right at install time. The published typescript-eslint package declares a peer dependency range that caps out below version 6.1.0, so npm rejects the resolution outright, surfacing an ERESOLVE failure instead of a soft warning. That's actually the more forgiving failure mode.

The rougher outcome shows up if you override the conflict and force the install anyway. With the mismatched packages in place, running lint crashes inside typescript-estree while it's building the program, tripping on a property access that no longer resolves to anything:

TypeError: Cannot read properties of undefined (reading 'Cjs')
    at .../@typescript-eslint/typescript-estree/dist/create-program/shared.js

Notice what that message doesn't say. It never mentions TypeScript 7, never flags a version mismatch, never says "unsupported configuration." It's a raw internal crash — which is exactly the complaint raised in issue 12518: the reporter asked for a clear, human-readable compatibility error instead of a stack trace, and as of now that request is still open.

Now apply the alias workaround described earlier and rerun the same commands. Lint works again, because it's quietly talking to TypeScript 6.0 behind the scenes, while npx tsc on its own still resolves to the faster 7.0.

While you're set up this way, it's worth timing your own build under both versions. That number, not anyone else's benchmark, is the one that should drive your decision — and it will almost certainly look far less dramatic than the VS Code figures, simply because your codebase isn't two million lines long.

What I take from it

What makes TypeScript 7 an odd case is that two contradictory readings of it are both accurate, and most coverage has only picked one.

It's a serious piece of compiler engineering that hands back real hours every week to teams that were losing them to slow builds. It's also a release that shipped only half of what it needed to, disclosed that fact deep in the announcement, and left the fallout for maintainers who had no say in the release schedule.

What would have been useful — and what didn't come through clearly at launch — is one plain sentence up top: this release is ready for your build pipeline, not for your tooling, and here's exactly what that means for you. That sentence was technically there. It was just buried several scrolls past the benchmark chart.

Version 7.1 is meant to actually close this gap. Until it does, the sensible approach is narrow: take the speed wherever it costs nothing, in your editor and in CI, and leave every tool that still imports the compiler directly exactly as it is.