typescript

They ported tsc to Go

They ported tsc to Go

In March, Anders Hejlsberg announced that the TypeScript compiler and tooling are being ported to Go, under the codename Corsa. The number attached was that the VS Code codebase — about 1.5 million lines — goes from roughly 78 seconds to type-check with tsc down to about 7.5 seconds. Ten times.

Six months on, the previews exist and the thing is real. I have been using TypeScript daily for years and waiting on tsc for most of them, so this is worth a note — but the part I keep thinking about is the language argument.

Why not C#

Hejlsberg created both TypeScript and C#, and Microsoft owns C#, so the obvious question got asked loudly and repeatedly.

The stated reason is that this is a port, not a rewrite. The existing compiler is a large body of TypeScript written in a particular style: functions over data structures, closures, structural typing, heavy use of shared mutable state through a checker that is deliberately not object-oriented. A port keeps the structure and translates it, which is how you preserve behaviour — including the edge cases nobody has written down, which in a compiler with this much history is most of the interesting behaviour.

Go maps onto that style closely. Functions and structs, no class hierarchy imposed on you, a garbage collector so ownership does not have to be redesigned, native compilation, and good concurrency for parallelising work across files. C# would have pushed the code towards a different shape, and a rewrite that changes shape is a rewrite that changes behaviour somewhere.

That reasoning is sound and I would apply it generally: when the requirement is "identical behaviour, much faster", the language you want is the one whose idioms are closest to the code you already have, not the one you like most.

It is also a striking thing to watch from outside. The most successful language project at Microsoft chose Go for its own compiler on technical grounds, in public, and explained why. That is a healthier way to make that decision than most organisations manage.

Where the speedup comes from

Two places, and the split matters for what to expect.

Native compilation removes the JavaScript engine's warm-up and gives better memory behaviour on the enormous graphs a type-checker builds. That is most of the baseline win and it applies to every project.

Concurrency is the rest. Type-checking has independent work in it — files that can be checked in parallel — and a single-threaded JavaScript process was never going to take it. How much that helps depends on the shape of your codebase, which is why a figure from one large project is a starting point rather than a prediction.

So I would expect the improvement on a small service to be real and unremarkable, and on a large monorepo to be the difference between running tsc in a watch loop and avoiding it. The projects that were suffering most will benefit most, which is the right way round.

What it changes in practice

Editor responsiveness more than build time, I suspect. The language service is the same engine, and in a big project the lag between typing and the editor understanding what you typed is a much more expensive tax than a CI step that runs while you do something else.

It also puts a dent in an argument I have made myself. Every conversation about TypeScript build performance for the last few years has ended with someone suggesting a faster tool that strips types rather than checking them — esbuild, swc, and now Node stripping types directly. Those are fast because they do less; they do not type-check. If the thing that actually checks becomes ten times faster, the "skip checking in development" compromise gets harder to justify.

What I am not doing yet

Putting it in a pipeline. It is a port of a compiler with a decade of accumulated behaviour, the whole promise is that the behaviour is identical, and the only way that promise gets tested is by large codebases running both and comparing.

The cheap and useful version is to run it alongside on a project I already have, compare the diagnostics with what the current compiler produces, and report anything that differs. That costs an afternoon, it contributes to the thing that makes the port trustworthy, and it tells me what the number looks like on my own code rather than on VS Code's.

Which is the same conclusion I keep arriving at with performance announcements. The figure is real, it came from a real workload, and it was not your workload.

Deyan Peev

Written by

Deyan Peev

Founding Engineer · Sofia, Bulgaria

Deyan Peev

Founding Engineer in Sofia, Bulgaria. Currently at 1club.

Elsewhere

© 2026 Deyan Peev