TypeScript 7 came out in July. It’s the release where the compiler stopped being written in TypeScript: the team ported it to Go, function by function, keeping the same checker logic, so code that is clean on 6.0 should get the same errors, only sooner (with small differences, such as the order of union members in messages, which 6.0’s stableTypeOrdering option previews). The package is still typescript and the command is still tsc.
I tried the upgrade on two of my projects: json2types, a small Vite app, and the monorepo behind the Arrows puzzle game. The type checks got five to six times faster, and my code needed no changes at all. What broke was everything around the compiler, and that’s what this article is about.
The numbers
Each figure is the median of three full type checks on the same 4-core machine (7.0 checks in parallel, so with more cores the gap is usually wider), TypeScript 6.0.3 against 7.0.2, with no errors either way:
| Project | What it checks | TypeScript 6 | TypeScript 7 | |
|---|---|---|---|---|
| json2types | 3 projects with tsc -b --force |
3.26 s | 0.55 s | 5.9× |
| Arrows | 4 tsconfigs, wall clock | 8.19 s | 1.62 s | 5.1× |
| Arrows, the game alone | 696 files (22,000 lines of our code plus libraries’ types), compiler’s own timing | 4.45 s | 0.77 s | 5.8× |
The game’s check also used about a quarter less memory: 237 MB of heap against about 316 MB, as --extendedDiagnostics reports it. Microsoft quotes 8 to 12 times faster on large codebases, such as VS Code’s, where a full build dropped from 126 to 11 seconds. Smaller projects gain less, because part of every run is fixed cost, like loading the standard library’s types, but five times faster is the difference between a pre-commit check you wait for and one you don’t notice.
What breaks: anything that imports typescript
Upgrading the dependency is one line. The first command after it failed:
$ npx eslint .
typescript-eslint does not support TS 7.0.
Please see https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0
to run typescript-eslint using the TS 6 API.
See also https://github.com/typescript-eslint/typescript-eslint/issues/10940 for tracking typescript-eslint's support for TS >=7.1
npm had already warned about it during the install: typescript-eslint 8.71 declares typescript >=4.8.4 <6.1.0 as a peer. Then the unit tests:
FAIL |unit| scripts/typescript.tsc.test.ts
TypeError: Cannot read properties of undefined (reading 'ES2022')
That test type-checks the TypeScript that json2types generates, in memory, through the compiler’s API (ts.createProgram and friends). TypeScript 7.0 doesn’t ship that API. Its package has tsc and a set of explicitly unstable/ entry points, and the stable programmatic API is planned for 7.1. So import ts from 'typescript' no longer gives you ts.ScriptTarget, and every tool built on the old API stops: typescript-eslint, ts-node, ts-jest, ts-loader and fork-ts-checker, vue-tsc, svelte-check, Angular’s compiler, TypeDoc, anything using ts-morph, custom transformers, and tests like mine.
Your bundler, by contrast, doesn’t care. Vite, esbuild and the other fast transpilers strip types without asking the compiler, so the build kept working throughout.
Advertisement
The fix: both versions, side by side
The TypeScript team publishes TypeScript 6 as a separate package, @typescript/typescript6, for exactly this period. The trick is two npm aliases: tools that import typescript get version 6, and the tsc command comes from version 7:
npm install -D "typescript@npm:@typescript/typescript6@^6.0.2" \
"@typescript/native@npm:typescript@^7.0.2"
# pnpm: pnpm add -D with the same two specifiers
"devDependencies": {
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2"
}
The TypeScript 6 package names its command tsc6, so the two don’t collide, and node_modules/.bin/tsc points at version 7:
$ ls -l node_modules/.bin | grep tsc # trimmed to the links
tsc -> ../@typescript/native/bin/tsc
tsc6 -> ../typescript/bin/tsc6
$ npx tsc -v
Version 7.0.2
With that, everything passed again: ESLint with type-aware rules, all 400 unit tests including the in-memory compiler ones, tsc -b (now on version 7) and the Vite build. Scripts such as "build": "tsc -b && vite build" didn’t change at all. (One oddity: the wrapper package is 6.0.2 but installs the 6.0.3 compiler, so npm ls and npx tsc6 -v disagree.)
Two things to keep in mind with this setup. ESLint’s type-aware rules and my compiler-API tests now run on TypeScript 6’s checker while tsc runs on 7’s. Since 7.0 is a faithful port that’s fine in practice, and it’s exactly the situation the TypeScript team designed the packages for, but it’s worth knowing when two tools disagree. And the aliases are temporary: when 7.1 ships its API and your tools support it, replace both with a plain typescript dependency again. Your own API code won’t simply come back with it, though: 7.1’s API is new and different, so a test like my in-memory compiler check will need porting.
Before you upgrade
- Clear the 6.0 deprecations first. TypeScript 6.0 deprecated a set of old options and changed several defaults; 7.0 removes those options. On 6.0 they’re reported as errors (TS5101) that
"ignoreDeprecations": "6.0"can silence; 7.0 rejects them outright. So remove that setting and fix everything it was hiding while you’re still on 6.0, where the old behaviour is available to compare against. Both of my projects were already clean on 6.0, which is why 7.0 needed no code changes. - Find everything that imports
typescript.npm ls typescript(orpnpm why -r typescript) lists the packages that depend on it. Linters,ts-morph, documentation generators and test helpers are the usual ones. - Check your editor separately. With these aliases the editor still runs TypeScript 6, unless you install the TypeScript 7 language service (Microsoft’s TypeScript Native Preview extension in VS Code). And the TS 6 wrapper has no
tsserver.jsinnode_modules/typescript/lib, so atypescript.tsdksetting or “Use Workspace Version” pointing there can fail; point it atnode_modules/@typescript/old/libinstead. - Measure your own project. My two are small. The gains grow with the codebase, and so does the relief.
What I’d keep in mind
- The compiler got faster; your code shouldn’t need to change. If 6.0 is clean, 7.0 most likely is too.
- The API is what’s missing in 7.0, and it’s planned for 7.1. Everything that imports
typescriptis affected, the bundler isn’t. - Run them side by side:
typescriptaliased to@typescript/typescript6for tools,@typescript/nativefortsc. - Plan to undo the aliases once your tools support 7.1, and to port your own API code.
Five times faster type checks for one changed line in package.json, and a second line to keep the tools happy, is the easiest performance win I’ve had this year.


