2026년 7월 8일
TypeScript 7 Is Not Written in TypeScript
Every post about TypeScript 7 will lead with the same number: ten times faster. The more interesting fact is the one the benchmarks bury. The compiler that checks TypeScript is no longer written in TypeScript. A look at why the team chose Go over Rust, why a port beat a rewrite, what it means that dogfooding lost, and whether you should actually move yet.
Sascha Becker
Author약 9분

TypeScript 7 Is Not Written in TypeScript
Every announcement post about TypeScript 7 will lead with the same number. Ten times faster. It is a real number and it is worth having. But the more interesting fact is one the benchmarks bury: the compiler that checks TypeScript is no longer written in TypeScript.
For over a decade the pitch for TypeScript has been a single promise. Types make large codebases survivable. And the compiler was the proof by example. It was one of the largest, most-forked TypeScript codebases in existence, and it was written in the language it checked. That was the dogfood. When the team decided the compiler needed to be an order of magnitude faster, they concluded that the way to get there was to leave. TypeScript 7 is a port of that compiler to Go.
That is the story worth writing. Not the speed. The decision to stop eating your own cooking, and what it says that the decision was obviously correct.
What actually shipped
Keep this part short, because everyone else will make it long.
TypeScript 7 is a native compiler. Same language, same type system, same output, roughly ten times the throughput. The team's published numbers, on real projects:
Memory use dropped by six to twenty-six percent across the same projects. In the editor, which is the more human measurement, surfacing errors across the VS Code codebase went from about seventeen and a half seconds to under one and a third.1 Slack reported cutting CI type-checking from seven and a half minutes to a quarter of that. The language server, the thing that actually decides whether your editor feels alive, reports over eighty percent fewer failing commands and sixty percent fewer crashes against the 6.0 baseline.
None of that required you to learn a single new type. That is the whole point, and we will come back to it.
Why Go, and why a port
The choice of Go set off the predictable fight. Why not Rust, the language that owns the "fast systems tool written by people who care about correctness" niche? The answer is not tribal, and it is more interesting than tribalism would be.
The TypeScript compiler's internal data structures are graphs. Abstract syntax trees, symbol tables, and type relationships are full of cyclic references: a node points at its parent, the parent points back, symbols reference types that reference symbols. Rust's ownership model is, by design, hostile to exactly that shape. You can build cyclic graphs in Rust, but you do it with arenas, integer indices, and reference counting, and by the time you have, you have effectively rewritten the type checker's memory model from scratch. That is a multi-year project with a built-in risk of subtle behavioral drift from the compiler millions of people already depend on.
Go goes the other way. It is garbage collected, it is comfortable with cyclic references, and goroutines give cheap shared-memory parallelism across a single symbol table. That combination is what let the team do a port instead of a rewrite. Anders Hejlsberg described Go as the lowest-level language they could reach that still gave them full native-code output on every platform, real control over data layout, and the ability to have cyclic data structures.2 Rust, as he put it, succeeds wildly at its own goals, and "straightforward to port this particular JavaScript codebase into" was rationally never one of them.
The word port is doing real work here. The Go implementation was, in the team's own description, methodically ported from the existing code rather than rewritten, and its type-checking logic is structurally identical to TypeScript 6.0.1 That is why it landed in about a year instead of never, and why you can trust that it types your code the same way the old compiler did. The one place they had to improvise was file watching, where Go's standard library came up short, so they ported Parcel's C++ watcher into Go with a few assembly shims rather than take on a new native dependency. Even the escape hatch was a port.
The heresy, examined
Here is the thing that should nag at you. The strongest possible advertisement for a language is that its own tooling is written in it and thrives. TypeScript had that. It gave it up on purpose.
You can read this two ways, and both are true at once.
The uncomfortable reading is that self-hosting was always partly theater. A compiler is a batch program that allocates enormous graphs, runs the same hot loops billions of times, and then exits. That is a workload managed languages are simply worse at than native ones, and no amount of loyalty to the brand changes the physics. The moment performance became the priority over principle, principle lost, and it was not close.
The generous reading is that this is what maturity looks like. Dogfooding is a means, not an end. Its job is to keep the people who build a tool honest about what the tool is like to use. TypeScript has a hundred thousand real codebases doing that job now. It does not need its compiler to be one of them. Keeping the language pure at the cost of every user's build time would have been the vain choice, not the virtuous one.
What I find genuinely clarifying is that the pragmatic choice and the ideological choice pointed in opposite directions, and the team picked pragmatism without any visible agony. Go over Rust because it fit the existing code. Native over managed because the workload demanded it. Port over rewrite because users needed identical semantics more than they needed a fresh design. Every one of those is the boring, correct, un-tweetable answer, and shipping all three at once is the actual achievement here.
Should you actually move
Now the practical half, because "it is faster" is not the same as "switch on Monday."
7.0 and 6.0 are designed to coexist. 7.0 adopts 6.0's defaults and turns anything 6.0 deprecated into a hard error, so the migration path runs through 6.0 first. There is a compatibility package, @typescript/typescript6, that installs the old compiler as tsc6 alongside the new one, so you can move a monorepo one package at a time instead of in a single leap.
The defaults shifted, too. strict is now true out of the box, module defaults to esnext, rootDir defaults to ./, and types defaults to an empty list, so global type packages have to be named explicitly. The breaking edges are worth reading before you upgrade in anger. A sample of what now hard-errors instead of quietly warning:
jsonc// TypeScript 7 rejects these outright. All were deprecated in 6.0 first."target": "es5", // gone; no more ES5 downlevel"downlevelIteration": true, // gone"moduleResolution": "node", // use "bundler" or "nodenext""baseUrl": "./src", // use relative "paths" instead"esModuleInterop": false, // can no longer be turned off"module": "amd" | "umd" | "system", // gone
And the constraint that will actually gate most teams: the embedded-language tooling is not ready. Vue, Svelte, Astro, Angular, and MDX all depend on a programmatic compiler API that the native port does not yet expose. That API is slated for 7.1. If your editor experience for .vue or .svelte files matters, and it does, you wait.
The honest verdict
The command-line and CI story is ready today: point the native compiler at
your build, feel the speedup, and keep tsc6 around for anything that breaks.
The editor story for framework single-file components waits for 7.1. Move your
type-check-in-CI job now. Hold your team's editors until the tooling you
depend on ships against the new API.
There is a fast lane for the impatient. The new --checkers flag controls how many type-checking workers run in parallel, four by default. The team measured a 16.7x speedup on VS Code by raising it to eight. --builders does the same for project references in a monorepo, and --singleThreaded turns it all off when you need a deterministic profile. These are the knobs that turn "ten times faster" into "as fast as this machine allows."
Until the tool disappears
The most honest thing about TypeScript 7 is how little it asks of you. No new syntax. No new types. Nothing to relearn. The entire release is the same language, arriving faster. That is easy to mistake for a boring release, and it is exactly backwards. The upgrades that change how the work feels without changing what you have to know are the rarest and most valuable kind. You notice TypeScript 7 the way you notice a road being repaved: not while you drive it, only in the absence of the pothole you had stopped seeing.
And the price of that was a quiet heresy. A language that sold itself on trusting types to tame big systems looked at its own big system and decided the honest move was to build it in something else. That is not a betrayal of the idea. It is the idea grown up enough to stop needing to prove itself on its own compiler.
- Announcing TypeScript 7.0
The release post. Benchmarks, the 6.0 and 7.0 coexistence model, the full list of new defaults and hard errors, and the parallelization flags.
- A 10x Faster TypeScript
The original March 2025 announcement of the native port, where Anders Hejlsberg first laid out the performance goal and the Go decision.
- Microsoft TypeScript Devs Explain Why They Chose Go Over Rust, C#
The clearest write-up of the Go-versus-Rust reasoning, including the cyclic-data-structure argument and Hejlsberg's own framing.
- microsoft/typescript-go
The native port's source repository. The place to watch the 7.1 programmatic API that unblocks Vue, Svelte, Astro, Angular, and MDX tooling.
