TypeScript 7.0 shipped a few months back. It replaced the old JavaScript-based compiler with a new one written in Go. Recently I listened to a podcast with TypeScript’s creator, Anders Hejlsberg. He explained why they made it.
I was curious why, indeed. Some of you might feel the same, that choosing anything other than Rust feels like a crime nowadays if you watch the comments on social media.
It wasn’t a rewrite
Anders explains that it wasn't a rewrite, it was a port. The assumption was that only by porting could they preserve the semantics and exact behavior of the existing compiler, which everyone depends on for backwards compatibility.
The main point he mentioned was that the previous compiler's code assumed the existence of garbage collection. Choosing Rust would've meant a complete rewrite for memory safety using borrow checking, which would lead to big changes in the code logic.
Let me show you the simplest hypothetical example so you get a glimpse of the strictness around memory safety in Rust compiler.
Go compiles this without complaint:
func main() {
v := []int{1, 2, 3}
first := &v[0] // points at the first number, 1
v = append(v, 4) // no room left, so Go copies everything into a new, bigger array
fmt.Println(*first) // prints 1, still correct. The old array wasn't deleted,
// Go's garbage collector keeps it around as long as
// `first` points at it. `v` and `first` now point at
// two separate arrays though.
}Rust’s compiler refuses to build this at all:
fn main() {
let mut v = vec![1, 2, 3];
let first = &v[0]; // points at the first number, 1 (a real reference, tracked by the compiler)
v.push(4); // ERROR: push needs exclusive access, but `first` is still watching v
println!("{}", first);
}Here's the full error output:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:4:5
|
3 | let first = &v[0]; // points at the first number, 1 (a real reference, tracked by the compiler)
| - immutable borrow occurs here
4 | v.push(4); // ERROR: push needs exclusive access, but `first` is still watching v
| ^^^^^^^^^ mutable borrow occurs here
5 | println!("{}", first);
| ----- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` (bin "playground") due to 1 previous errorRust's compiler does a great job catching potential memory bugs at compile time without needing a garbage collector, but that would mean rewriting the approach completely. It would've been like solving a whole bunch of new problems.
Besides garbage collection, TypeScript's team needed to tick a few boxes, and Go delivered on all of them: performance improvements, robust and mature native code generation across all major platforms, and excellent support for shared-memory concurrency. So for this particular workload, Go was the right choice.
My sense is they wanted benefits with less work. That’s why they went with Go. That’s a fair point.
What does a faster TypeScript mean?
To close things out, let me share the results the TypeScript team got, as they shared them in the official Microsoft engineering blog.
“Today we are proud to announce the availability of TypeScript 7, a 10x faster native port of TypeScript!”
Conclusion
Honestly this whole story is a reminder that everything in engineering, like in life, comes down to tradeoffs. So yeah, Go wasn’t the flashy pick. It was the right one for the job. They needed speed and solid native compilation without rewriting a decade of the compiler logic around Rust, and Go got them there.
Thanks for reading,
Adlet Balzhanov
Connect with me on LinkedIn, just use the button below. I read every message. Cheers!





