Creator of TypeScript: 10x Faster Typescript, Why AI Won't Replace SWEs | Anders Hejlsberg

Executive Summary
Ryan Peterman interviews Anders Hejlsberg about TypeScript's origins, the native rewrite of its compiler, programming-language design, and software engineering in the age of AI. Hejlsberg explains that TypeScript began in JavaScript because self-hosting kept the project inside its target ecosystem and enabled broad tooling and platform reach. He describes the native rewrite as a performance and scalability project, with shared-memory concurrency and multi-core utilization as important motivations. The team chose to port the existing compiler to preserve semantics and compatibility rather than start over. The conversation closes with a cautious view of AI-assisted programming: agents can write substantial amounts of code, but engineers still need to understand, review, and take responsibility for the result.
Chapters & Key Takeaways
6 takeawaysHejlsberg describes self-hosting in the JavaScript ecosystem as an early strategic advantage for TypeScript.
The native compiler rewrite is presented as a response to compute performance, scalability, and concurrency constraints.
The rewrite was a port intended to preserve existing semantics and backwards-compatible behavior.
TypeScript's type system is described as primarily serving developer tooling rather than changing runtime behavior.
Hejlsberg rejects the idea that AI-generated code removes the need for engineers to understand and review the work.
The interview frames software engineering as shifting toward supervising and reviewing agent-produced code while retaining human responsibility.
Deep Read
Why TypeScript Needed a Native Rewrite, and What AI Programming Changes
Anders Hejlsberg explains that TypeScript began inside the JavaScript ecosystem because self-hosting made the team daily users of the language and its tools.
Read the full articleInterview Highlights
9 exchanges- Q
Why was the TypeScript compiler originally written in JavaScript?
Ryan Peterman asked01:15AAnders Hejlsberg answeredNo, it's a good question. Honestly, if you had told me before the TypeScript project started, "Anders, you're going to be writing compilers in JavaScript," I'd have said no. The original prototypes for TypeScript — the Strata project, as it was called in the very early days — were actually written in C, as an adaptation of the JavaScript parser we had in IE, and then we moved to JavaScript but wrote it sort of C-style. Why did we go with JavaScript? If you can self-host in the ecosystem that you want to be a part of, that is dramatically better than putting yourself outside the ecosystem and trying to target it. By writing it in TypeScript, we were daily users of TypeScript and of the tooling we were building; whenever something didn't work right or didn't perform, we knew it immediately. In the early years that was a huge boon. JavaScript also runs everywhere, so our compiler could automatically run on every platform, even in the browser — a native-code solution at that time couldn't have run in the browser, and WebAssembly didn't exist yet. And people didn't really realize how fast JavaScript had gotten: Google's work with V8 brought it within two to 3x of native code, which is pretty darn impressive. It was fully possible to write performant compilers in JavaScript, because often it's the algorithms that determine how performant you are, not necessarily the runtime environment.
- Q
Is there anything unique about the TypeScript compiler?
Ryan Peterman asked03:39AAnders Hejlsberg answeredI think there are a couple of things that are pretty unique about TypeScript's compiler. First of all, it doesn't target machine code — it targets JavaScript; some people call that a transpiler, and in a sense the compilation phase is mostly about removing the type annotations and turning your TypeScript back into JavaScript. In the early days an important part of the compilation process was also to downlevel your JavaScript, because the runtime environments at the time were not evergreen — some lagged multiple years behind the standard. When classes got standardized, most JavaScript runtimes didn't implement them, but it turns out you can downlevel to constructor functions and transform the code. And then of course the type checking is the big thing. The type checker in TypeScript is quite unlike any other type checker in other compilers: typically type checkers exist to guide the code generator, but since we erase the types, the types have no impact whatsoever on the runtime behavior of the code. They purely exist for tooling sake and for the developer sake, to guide things like statement completion, refactoring, and code navigation. TypeScript also has a gradual type system: you can have half of your code typed and the other half is just any, and very few languages have anything like that. That actually made it fascinating to work on, because we were solving problems that no one had solved before.
- Q
So with the the native rewrite of this originally fully JavaScript compiler, what was the problem you were trying to solve with the rewrite and why did you end up write rewriting it in native code?
Ryan Peterman asked07:29AAnders Hejlsberg answeredThe problem we were trying to solve is real simple: performance and scalability. JavaScript was never really optimized for compute-intensive workloads like compilers — it's more about creating UI that runs in a browser. In JavaScript, first of all, you pay a 2 to 3x performance penalty compared to native code; it depends on the workload, but for compute that's about where it's at. And secondly there are a lot of restrictions around use of concurrency. JavaScript was always engineered to be a single-threaded language — that's why we have callbacks and async, because you can't spin up threads. That's mostly a good thing, because concurrency in a language with mutable data is very hard: you can have races and deadlocks and all of that. Functional programming languages are easier with concurrency because all the data is immutable. JavaScript doesn't give you access to concurrency other than web workers, and web workers can't share data between each other other than by remoting it — one worker has to turn data into JSON to hand it to another. In other words, you can't have shared-memory concurrency, and really that's what we wanted in order to gain the performance we were leaving on the table by not utilizing the multi-core CPUs everyone has today. Moore's law has stopped giving us faster CPUs; it's giving us more CPUs, and we were leaving money on the table in multiple ways. So we looked for a language that would get us out of both of those binds: it had to be native, and it had to have access to shared-memory concurrency.
- Q
I saw for the language choice you went with Go. And when I think of all the systems languages, the ones that are often hot or maybe you know Rust or Zig, why did you choose Go for the native rewrite?
Ryan Peterman asked10:24AAnders Hejlsberg answeredThe decision process was actually pretty structured. The first decision we made was: we're not going to rewrite, we're going to port — because only by porting can we preserve the semantics and the algorithms and the exact behavior of our existing compiler, which everyone depends on for backwards compatibility. We could have cleaned the slate and started completely from scratch, but we would have come up with a different language, in the sense that it would give you different errors or behave differently in situations where it has to make choices between multiple possibilities. Porting also meant our code could keep certain assumptions — for example our code assumes the existence of garbage collection, and first-class treatment of functions: you can have functions within functions that close over state. As we evaluated all of these, Go was the one that checked the most boxes. It gives us very robust and mature native code generation on all major platforms, it has garbage collection, and it has excellent access to shared-memory concurrency. Those were the high-order bits we wanted to check, and every other language had something that kind of worked against those objectives. So for this particular workload, Go was the right choice for us, and it's worked out well.
- Q
If you think about Rust, what didn't it have that, if it had, you would have picked it?
Ryan Peterman asked12:16AAnders Hejlsberg answeredI think there are two things. It doesn't have garbage collection — it's done manually, or through the borrow checker, and the borrow checker doesn't allow circular data structures. Our compiler is chalk full of circular data structures: we have trees with parent pointers, types that are recursive, symbols that refer to each other — it's everywhere. If we had chosen to rewrite, we could probably have solved all of that, but it wouldn't have been just porting the code; it would also have been solving a whole bunch of new problems we had bought ourselves by going that route. We tried, and it just wasn't feasible. We were just trying to optimize for doing as little work as possible to get us to the payout. And honestly, Rust is no better when it comes to the quality of the generated code or the concurrency gains we could have gotten out of it — Go is just as great. We got all the benefits for less work by going that route.
- Q
Do you think AI will write more than 90% of the code within a year, and if so, when might that happen?
Ryan Peterman asked51:33AAnders Hejlsberg answeredFor certain classes of apps, they're writing 100% of the code, and there's an awful lot of that being written. Are they going to write 90% of the high quality code on the internet? I don't know about that. Ninety percent of the volume of written code is just going up like that right now, because AI writes so much code — so in a sense that's a self-fulfilling prophecy. But when it comes to the super high quality code that no one has ever written before, it's not clear to me that AI is going to write 90% of that.
- Q
What is the hardest piece of code you've ever written or what's the most technically challenging thing you've ever done?
Ryan Peterman asked58:59AAnders Hejlsberg answeredThere are so many things that in their time were challenging. On this last project, the easy part was getting the native code — just move it to another language. The hard part was taming this beast called shared-memory concurrency, and getting the compiler to use as many CPUs as there are available on your box. That is not a simple problem to solve in a compiler, because we're all taught to write sequential code: first you do this, then you do this. How do you do all of this at the same time, and then share the data structures afterwards, without anyone accidentally modifying the other guy's data structure? And in the cases where you have to do that, how do you synchronize it and avoid deadlocks and race conditions? It was tricky — there were some good technical problems that we licked that I think we can be proud of.
- Q
Is there a top technical book recommendation you have for software engineers?
Ryan Peterman asked01:02:06AAnders Hejlsberg answeredI usually recommend the same one. The book that was the "it" book for me when I was younger is Algorithms Plus Data Structures Equals Programs by Niklaus Wirth, the inventor of Pascal and later Modula and Oberon. It's a book that is light on math and symbolism and rich in instructive examples and good explanations about how data structures work. That's how I learned about hash tables. When you're self-taught, you don't know about hash tables — you sort of know about linked lists. In the original version of Turbo Pascal, all the symbol tables were just linked lists, and as you had many local variables you were going exponential in search time. Then I read about these hash tables — wow, you mean I can do this and it's basically linear lookup time? I implemented it and the compiler got twice as fast. Holy cow, that was useful reading. He also explains how to do error recovery when you construct a simple compiler. It was a great book for me — and now it's just a big PDF you can download out there; it's been out of print for 30 or 40 years.
- Q
Last question for you is with all the experience that you have now, if you could go back to yourself when you just entered the industry and give yourself some advice, what would you say?
Ryan Peterman asked01:03:50AAnders Hejlsberg answeredA couple of things, maybe. Like we talked about, being a team player — I would probably have tried to educate myself a bit more about that to begin with. And one thing in retrospect: don't let people tell you that it can't be done. When they tell you it can't be done, it's because they can't do it. That doesn't mean that you couldn't possibly do it. So don't let that discourage you.