Add Go's `defer` to the TypeScript compiler: an educational patch in a Go-written compiler

Dev & Code 32 min agoAdd to bookmarks

Add Go's `defer` to the TypeScript compiler: an educational patch in a Go-written compiler
Illustration : Momiji Shirogane

Andrew Healey injects the `defer` keyword—pillar of Go code—directly into the TypeScript compiler, now written in Go. A textbook case for understanding parser, checker, and emitter.

The Starting Point

Since Microsoft announced the rewriting of the TypeScript compiler in Go (the "TypeScript Native" project, aiming for ~10× speed compared to the historical tsc in TypeScript), the compiler's source code has become a fantastic playground. Andrew Healey published a very educational article on his blog where he adds the defer keyword—one of Go's ergonomic pillars—to TypeScript in his fork.

For those coming mainly from the JS stack: in Go, defer schedules a function to run when the enclosing function returns. It's equivalent to a try { … } finally { … } without the boilerplate, with the cleanup call written right next to the call that made it necessary:

f, _ := os.Open("file.txt")
defer f.Close() // will execute when exiting the function
// … rest of the code

The pattern is widely used to release resources (files, mutexes, connections) without getting lost in nesting.

What This Breaks Down

The article's value isn't "Go's defer will be in TypeScript tomorrow" (spoiler: no). It's about following, step by step, what a modern compiler does when a keyword is added. Healey goes through:

  1. The scanner (lexer) – recognizing defer as a dedicated token rather than an ordinary identifier.
  2. The parser – deciding where defer is allowed in the grammar (at the statement level, yes; in expressions, no).
  3. The checker (type-checker) – ensuring what is deferred is indeed a function call.
  4. The emitter – translating defer into JavaScript, which, in his case, involves wrapping the enclosing function in a try/finally and stacking deferred callbacks in an array executed during unwinding.

This last step is the most instructive: defer in Go is a true language mechanism (implemented by the runtime), whereas in JS, we have nothing comparable—so it must be simulated via desugaring, with the trade-offs that entails (performance, exceptions, await, etc.).

Why This Matters to Us

With the TypeScript compiler rewritten in Go being open source, this kind of exercise is exactly what you should read to:

  • Understand the architecture of a real modern compiler (not a toy).
  • See how a target language (JS) constrains translation choices when it lacks the needed primitive.
  • Get familiar with the AST → typechecking → emission pipeline, on a project whose surface you already know (tsc).

We note in passing that Healey's patch is presented as a demo, not an upstream PR—the TC39 has never adopted defer for standard JavaScript, and Microsoft isn't pushing a proprietary extension of this kind in TypeScript.

To remember: the real gain of Go's rewrite of tsc isn't just speed—it's also a compiler whose code is finally approachable for a reader who isn't an expert in advanced TypeScript. This kind of pedagogical patch will multiply, and it's an excellent school.

Resources, try it

Article produced by artificial intelligence, reviewed under human editorial control.

Our newsroom
Was this article helpful?

7 people liked this article

Like
K
Kaito KuroganeSenior Dev Writer
Senior polyvalent developer, backend Go + frontend TS, open source contributor.
Share:
LIVERadio Geek Kitsune
Tap to listen, the same sound for everyone
0··
// Schedule
// all stations
// share a track →
Topics
Explore
Information