TypeScript is being ported to Go. This is known as “TypeScript 7” (it is currently on 5.8). It’s quite likely that you know this by now, as there have been excellent communications from the TypeScript team. In fact, hats off to the team; it’s been an object lesson in how to communicate well: straightforward, clear, and open.
There’s no shortage of content detailing what is known about the port. This piece is not that. Rather, it’s the reflections of two people in the TypeScript community:
ts-loader
, the webpack loader for TypeScript. In his day job, he works at Investec, a South African bank, and is based in London. The greatest city on earth (in his opinion)It’s going to be a somewhat unstructured wander through our reactions and hopes. Buckle up for opinions, thoughts, and feelings.
I mean, weren’t we happy with each other anyway? Just as we were? Yes, but also no.
If you’ve been in the JavaScript/TypeScript ecosystem recently, you’ve probably noticed a growing number of tools that support JavaScript development — but are written in other languages. We’ve had esbuild, written in Go. SWC, written in Rust. Bun, written in Zig. Deno, written in Rust.
The list kept growing. All of these tools brought performance gains, which was — and still is — a wonderful thing. We’ll talk more about performance later. One hold-out was TypeScript. It continued to be written in TypeScript. While performance improvements did happen — and were an area of focus for the team — they were incremental, not transformative.
You could sense the impatience in the community, as people started trying to speed up TypeScript by building their own implementations. Most notably, DongYoon Kang, the creator of SWC, implemented the transpilation aspect of TypeScript. He then attempted to build a type checker as well — first in Rust, then in Go, then back to Rust.
That project didn’t ultimately succeed, but the fact that people were willing to try showed how strong the demand for better performance had become. A successful port seemed inevitable — and if it didn’t come from the TypeScript team, it could have put the ecosystem in a tricky spot. A port to a language other than TypeScript was going to happen eventually. And here we are.
What does the Go port meaningfully change about TypeScript? According to Josh Goldberg‘s useful framing, TypeScript is four things:
The language is unaffected by the port. Syntax is unchanged. You’ll still be writing type
s and interface
s as you were before. There is no difference.
The same applies to the checks that the type checker is performing. The code that was detected as an error before will still fail to type check with TypeScript 7:
const i: number = "not actually a number"; // ts: Type 'string' is not assignable to type 'number'
This is where the differences begin. The type checker, compiler, and language services do change. They become an order of magnitude faster.
Put your hand up if you don’t care about performance. That’s right — no hands went up. We all care about performance. Whenever you have to work with technology that lags and breaks you out of your flow, you notice it. It’s basically all you notice.
The TypeScript team has always cared about performance, particularly in the area of development tooling. TypeScript co-creator Anders Hejlsberg has mentioned in interviews the need for language servers to provide fast feedback as people work — something measured in milliseconds, not seconds.
What are the implications of these changes to the TypeScript ecosystem? Put simply, a faster VS Code and faster builds.
At Investec, where John works, there are many engineers who use VS Code and spend part of their engineering life writing TypeScript and JavaScript. All those engineers will benefit from a snappier development experience. When they open up a project in VS Code, the time it takes for the language service to wake up will drop dramatically. As they refactor their code, the experience will be faster. The “time to red squiggly line” metric will decrease. That’s a good thing.
As a consequence, engineers should be incrementally more effective, given that there are fewer pauses in their workflow.
The same incremental gain applies to builds. As our engineers build applications, they run TypeScript builds on their machines and in a continuous integration context. These will all be faster than they were before. We’ll continually experience a performance improvement, which is a benefit.
This, of course, is not Investec-specific but a general improvement that everyone will benefit from. Across the world, wherever anyone writes and builds TypeScript, they will do so faster.
Many languages have bootstrapping compilers, meaning the compiler is written in the same language it compiles. TypeScript has followed this model since it was first open sourced. That’s about to change: the compiler will no longer be written in TypeScript, but in Go. This may be the first example of a language intentionally moving away from a bootstrapping compiler — and it’s all in the name of performance.
Of all the aspects of the Go port, this, according to John, is the most anxiety-inducing. The TypeScript team will be writing less TypeScript in their day-to-day work. They won’t stop using it, of course, but they’ll certainly be writing more Go and less TypeScript. One implication of this is reduced dogfooding, meaning less direct feedback from the people building the language about what it’s like to use it.
That said, given how broad and active the TypeScript community is, this may not be as concerning as it first seems. The team is highly connected to the community and, even if they’re writing less TypeScript themselves, there are plenty of others who will continue to provide feedback. It’s also worth remembering that the TypeScript team has often written the language in ways that don’t necessarily reflect how most developers use it. For example, they’ve historically relied heavily on classes (which we’ll talk about more below) and, until recently, modules. Before Jake Bailey’s monumental effort to migrate the TypeScript codebase to use modules, it was still using namespaces. That didn’t prevent the team from continuing to improve support for modern JavaScript features.
Another potential concern is whether the TypeScript team might become less involved in TC39, the committee responsible for evolving the JavaScript language. The TypeScript team has been instrumental in shaping JavaScript over the years, contributing to features like optional chaining, decorators, and more. As they shift to writing more Go, some have wondered whether their influence on JavaScript might diminish.
Ashley, who is one of Bloomberg’s TC39 delegates, isn’t worried. Daniel Rosenwasser, the Principal Product Manager for TypeScript, recently became one of TC39’s two incoming facilitators. Ron Buckton, another delegate from the TypeScript team, continues to champion several exciting proposals, such as Explicit Resource Management. The TypeScript team’s input remains just as important, regardless of what language the compiler is written in.
There are four primary ways to interact with the TypeScript package:
tsc
import ts from "typescript
tsserver
Let’s contemplate how these might change.
tsc
There will still be a CLI and it sounds like the goal will be very close compatibility. The implementation may change to be Go, but you would still be able to interact with the CLI in the same way.
import ts from "typescript
The TypeScript team are still working on this part. There will still be a JavaScript API, though it’s almost certain that there will be changes here. Exactly how different they are is not yet known. One core question is whether the currently synchronous API will need to become asynchronous due to calling Go, as this can be a difficult change to migrate to. The good news is that it looks like it will be able to retain a synchronous API.
tsserver
Editors such as VSCode, and even linters, can interact with TypeScript via its language server. Interestingly, even though TypeScript helped inspire the LSP specification, currently, it doesn’t actually implement it. The TypeScript team is using the port as an opportunity to align with the LSP specification, which is a positive change.
Tools use one or a combination of the above to use TypeScript on their user’s behalf. There will be work for the tools, but this might be done transparently to the end developer.
Let’s drill further into tools that use TypeScript internally. There will be an impact.
John is the maintainer of ts-loader
, a widely used webpack loader for TypeScript. This loader depends upon TypeScript APIs that have been unchanged in years.
In fact, John went so far as to comment on Bluesky in early March:
— only to have the TypeScript team effectively come out and say “hold my beer”.
It’s very early days, but we know for sure that the internal APIs of TypeScript (that ts-loader
depends upon) will change. To quote Daniel Rosenwasser of the TypeScript team:
While we are porting most of the existing TypeScript compiler and language service, that does not necessarily mean that all APIs will be ported over.
ts-loader
has two modes of operation:
It’s very unlikely that TypeScript 7 will work with ts-loader
’s type checking mode, without significant refactoring. However, it’s quite likely that ts-loader
might be able to support transpilation-only mode with minimal changes. This mode only really depends on the transpileModule
API of TypeScript. If the transpileModule
API lands, then the transpilation-only mode of ts-loader
should just work. On the other hand, this might be the natural end of the road for the type checking mode of ts-loader
.
Ashley is the author of ts-blank-space
, an open-source TypeScript-to-JavaScript transform published by Bloomberg that avoids the need for source maps. It also depends on TypeScript’s API, so it may be affected by the port. It’s too early to say, but the change here may turn into an opportunity.
A not-uncommon request of ts-blank-space
is to investigate using a different parser. This is because while ts-blank-space
itself is very small and only uses TypeScript’s parsing API, this is not an isolated part of TypeScript, so it still ends up importing the whole type checker. For projects that already depend on TypeScript, there is no added cost, but it makes ts-blank-space
less appealing for use cases that are not already importing TypeScript as a library.
Some tooling will have a natural path forward. For instance, typescript-eslint
will continue onwards with TypeScript 7. The TypeScript team are planning to help with typed linting with the new, faster APIs. So this means that ESLint, which many people are used to using, will become faster as TypeScript becomes faster.
However, it’s likely tooling that depends upon internal TypeScript APIs, which are going to radically change, may cease to exist in their current forms. This will vary project by project, but expect change. And this is fine — change is a constant.
Once it became clear that TypeScript would no longer be written in TypeScript, people naturally had strong opinions about what language should take its place. Fans of C# wished the team had picked C#, especially given Anders’ involvement with the language. Rust enthusiasts hoped for Rust. The good news for those folks is there’s still a chance Rust will play a role: the Node.js bindings for TypeScript 7 may use a Rust-based package.
If John had been asked to guess the replacement language ahead of time, he would’ve said Rust or maybe Zig (which Bun is built with). Go felt like a bit of a leftfield pick — but in hindsight, it makes total sense. ESBuild is written in Go, so there’s a successful precedent. Go has a garbage collector (unlike Rust), which makes porting the codebase significantly easier. Meanwhile, C# leans heavily on classes, whereas the TypeScript compiler makes only light use of them, so porting to C# would have been an uphill climb.
The choice of Go reflects pragmatism, which has always been at the heart of TypeScript’s ethos. In fact, if you look at TypeScript’s official design goals, you’ll see it again and again. Perhaps most famously, soundness is listed as a “non-goal.” Instead, TypeScript aims to strike a balance between correctness and productivity.
Bottom line: pragmatism is the TypeScript way, and Go is a pragmatic choice.
This is evidence that JavaScript can be a slow language in which to implement a type checker. To borrow a line from Anders’ “Why Go?” post:
No single language is perfect for every task.
Type checking is an intensive task. One way to think about it is that the type checker emulates the execution of a program, line by line, and detecting when that emulation breaks a rule. The larger the program, the more work there is to do.
When the type checker is written in a dynamic language, it requires another program to run it. In TypeScript’s case, we essentially have a JavaScript engine running the TypeScript checker, which is running an emulation of another program. It’s no surprise that running the checker natively would be noticeably faster.
Switching to Go brings a reported 10× speedup. That gain is roughly split: around 3.5× from running natively, and the rest from better parallelization:
Given how much more work it takes to execute code in a dynamic language versus a precompiled native binary, if anything, it’s actually impressive that the difference isn’t even greater. That speaks to the extraordinary performance work that’s gone into V8, the JavaScript engine used by Node.js.
It is possible to write JavaScript programs that work in parallel today, but doing so efficiently often requires low-level APIs like SharedArrayBuffer
, which force you to work with raw bytes. There’s a Stage 2 proposal to introduce Shared Structs to JavaScript. If that moves forward, it could make it easier to take advantage of multiple cores in JavaScript applications.
Of course, JavaScript still has many strengths. For example:
The ecosystem demanded a faster TypeScript. Performance cannot be ignored these days. As a consequence, some kind of port of TypeScript was bound to happen. If we accept that view, then what next? Well, the way that the TypeScript team has started executing on the migration fills us with confidence. The TypeScript team are talented, they are pragmatists and their choices are wise.
This is going to Go well.
Thanks to Jake Bailey, of the TypeScript team, for reviewing this piece – greatly appreciated! Also to Josh Goldberg for writing up his classification of what makes up TypeScript; many thanks!
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowDiscover open source tools for cross-browser CSS testing like Playwright and BrowserStack to catch rendering errors, inconsistent styling, and more.
Build a TypeScript ETL pipeline that extracts, transforms, and loads data using Prisma, node-cron, and modern async/await practices.
Looking for the best React charting library? Compare the latest options, from Recharts to MUI X Charts, and see which one fits your project best.
Explore six powerful RAG techniques to enhance LLMs with external data for smarter, real-time AI-driven web applications.