TypeScript with Jake Bailey

15 Jul 2025 · 46 min

Ask about this episode

Ask anything about it. ChatGPT or Claude reads this page and answers with the times it was said.

Connect VO and ask about every podcast you hear, including the moments you saved. Add to ChatGPT · Add to Claude

In short

Podcast Notes: TypeScript with Jake Bailey

Episode Overview Podcast Title: Software Engineering Daily Episode Title: TypeScript with Jake Bailey Host: Josh Goldberg Guest: Jake Bailey, Senior Software Engineer at Microsoft

Description: This episode dives into TypeScript, a statically typed superset of JavaScript that enhances code safety and developer productivity. Jake Bailey discusses his journey, contributions to TypeScript, and the future of the language, including its migration to Go for performance improvements.

---

Key Concepts

What is TypeScript?

  • Statically Typed: TypeScript allows developers to add optional type annotations.
  • Compiler Features:
  • Type Checking: Catches errors at compile time.
  • Transpilation: Converts TypeScript into standards-compliant JavaScript.

Guests and Hosts

  • Jake Bailey: Senior Software Engineer at Microsoft, contributing significantly to TypeScript.
  • Josh Goldberg: Host of the podcast, an open-source developer, and author of the O'Reilly Learning TypeScript book.

---

Key Takeaways

Jake Bailey's Journey into Programming

  • Early Beginnings: Introduced to coding in elementary school with a TI-73 calculator.
  • Academic Path: Studied computer science at Illinois and worked at Microsoft for six years, initially in Site Reliability Engineering (SRE) before shifting focus to programming languages, including Python and then TypeScript.

Contributions to TypeScript

  • Initial Work: Began with bug fixes and then transitioned to major projects like the migration to ES modules from CommonJS.
  • Module Migration: Improved performance and code organization.

Performance Improvements

  • ES Modules vs. CommonJS:
  • Predecessor: TypeScript used namespaces which slowed performance.
  • Outcome: Migration led to a 30-40% speed increase in compilation times and improved test start times.

DefinitelyTyped and Type Definitions

  • What is DefinitelyTyped? A repository of type definitions for libraries that lack their own TypeScript definitions (e.g., React).
  • Recent Changes: Transitioned to a PNPM monorepo setup for better management of type definitions.

---

Migration to Go Overview of the Transition

  • Reason for Migration: Performance limitations of TypeScript written in TypeScript.
  • Results: The Go version of TypeScript showed a 10x performance increase in compiling large codebases.
  • Concurrent Processing: Utilizing Go's concurrency model for parsing and type checking.

Implementation Strategies

  • Automation Tools: Developed tools to assist in the code transformation from TypeScript to Go.
  • Incremental Porting: Strategy allowed for a smooth transition while maintaining code behavior.

Future Implications

  • Potential Enhancements: Plans to further integrate TypeScript with WASM and additional features, leveraging the improved performance.
  • User Feedback Integration: Ensuring that user needs guide future improvements and features.

---

Conclusion The conversation touches on the evolution of TypeScript, the importance of performance in development tools, and the innovative transition of TypeScript to Go to enhance its capabilities. Jake Bailey's insights provide a glimpse into the future of TypeScript and the ongoing efforts to improve the developer experience.

---

Additional Resources

  • Jake Bailey's Website: [JakeBailey.dev](https://jakebailey.dev)

For more details, listen to the full episode [here](https://softwareengineeringdaily.com/2025/07/15/typescript-with-jake-bailey/).

Written by AI. May contain mistakes. Listen to the episode to check what was said.

Hear the part that matters, and keep it.Open this episode in VO. Double tap your headphones to save a moment as you listen.
Get VO free

Transcript

Automatic transcript. May contain errors.

0:00TypeScript is a statically typed superset of JavaScript that adds optional type annotations and modern language features to improve developer productivity and code safety. The TypeScript compiler performs type checking at compile time, catching errors before code is run, and also transforms TypeScript code into clean, standards-compliant JavaScript. Jake Bailey is a senior software engineer at Microsoft, where he works on TypeScript, and has made major contributions to the TypeScript compiler. Jake joins the podcast with Josh Goldberg to talk about TypeScript and his work. This episode is hosted by Josh Goldberg, an independent full-time open-source developer.

0:40Josh works on projects in the TypeScript ecosystem, most notably TypeScript ES Slint, the tooling that enables ES Slint and Prettier to run on TypeScript code. Josh is also the author of the O 'Reilly Learning TypeScript book, a Microsoft MVP for developer technologies, and a live code streamer on Twitch. Find Josh on Blue Sky, Mastodon, Twitter, Twitch, YouTube, and.com as Joshua K. Goldberg.

1:19Jake Bailey, welcome to Software Engineering Daily. Hello. How's it going? It's good. I'm so excited to talk to you, Jake. We've done so much work and you've done so much work on TypeScript and its tooling. Don't be bashful. What is your blue sky description? Your profile say? I think my profile says, according to GitBlam, I wrote the TypeScript compiler, which is not true, but it is true if you don't bother to ignore all the migrations I made. So, yes. Then I guess if you look at the new repo, then it'll probably also say something similar, but... There we go. Less so. The one and only author of TypeScript.

1:56No, no, no, no. Absolutely not. I'm new, okay? Well, we're going to get into that. But before we go through all the tooling stuff you've done with TypeScript and the work on TypeScript in Go, which is incredibly exciting, let's start with you. How did you get into coding, Jake? Ooh, a long time ago, I was a child in elementary school and I had a TI-73. And by some coincidence, the teacher assigned an assignment, which was basically, I want you to tell the class about a button on the calculator. And I'm pretty sure I got assigned the program button. And so I had TI-Basic. And so my first Spriter language was TI Basic in like, I don't know, the third grade, fourth grade.

2:44I don't know. One of those. But a lot of time, obviously. And then I just it's one of those things where it's like I kind of think I knew what I was going to do from the beginning. And I think like in middle school, I'm like, I'm going to check out the book on C. And I just learned C. And then I was like, man, I'd really like to work on RuneScape private servers. So that I'm just like modifying Java and like trying to convince my friends to install Hamachi so they can play on my private server and never succeeding. And then, you know, bubbles from there all the way up. Right. So, yeah. And then I went to Illinois for computer science.

3:20Did that. It was great. And lots of work otherwise. And I've been at Microsoft for, oh, my gosh, what, six years now? Something like that. I don't remember how old I am most days. So remembering when I did something is always a challenge. Do you remember what it was that drew you to programming in the first place? I have no idea, honestly. I had just always been the basement computer guy, I think. Like quite literally, that's where the computer that I had was located. So I just spent all the end of my days sitting, futzing around on the computer doing stuff. So when you went into Microsoft, it wasn't originally for TypeScript, was it?

3:54No, actually not at all. In fact, it's funny. I'd worked there the year before as an intern doing something completely different. Everything I did beforehand was like SRE work. I'm not sure if you're familiar with what an SRE is. Let's say I'm not. It's like a site reliability engineer. So it's kind of like people that work on infrastructure and like support other teams and do all that kind of stuff. And I did that at like, you know, basically three different companies at that point. But then I was at Microsoft and then I was like, you know, I'd like to try to interview to see if I want to move over to DevDiv to do some programming language stuff.

4:26Because at that point, I was in the middle of my grad degree and I was taking so many programming language classes. And I was like, this is awesome. And I'm like, let me go see if they'll hire me. And then I'm going to tell a longer story, the origin of this. But like they interviewed me and it was terrible because I got put through all the rounds. And it was such a long day. I was so tired at the end of the day. And then I found out afterwards that because I did SRE work, my title was service engineer, not software engineer. So they thought I had no programming experience. And so they put me through extra steps that I didn't need to do.

5:02And then they apologized afterwards. And they're like, oh, we're sorry. We didn't realize you were in a software engineering role. And I'm like, yeah, yes, I am. What the heck? So then I got hired and I was actually going to be on the C++ team working on the C++ compiler. And the last minute I get an email and says, hey, you're going to work on Python. And so I'm like, okay. And so I spent the first couple of years working on Python. So working on Python language server, editor stuff, later on PyLance, PyWrite. So PyWrite is a type checker for Python. And I worked on that. And then eventually I switched over to TypeScript, trying something new.

5:37And I've been on that for the past three years, something like that. I don't know. I don't have a calendar in front of me to tell me what I did. But I think maybe three years now. One of the nice things about open source is that it's all in the public. After this, we can go and see exactly when you started. Yeah, yeah, yeah, absolutely. Absolutely. Do you remember what you were doing when you first joined the TypeScript team? Ryan, our engineering manager, he assigned me a bunch of bugs. This is pretty common when people join the team is that he'll assign them a bunch of bugs that are sort of like, get you started.

6:07And I had joined and Pyrite, if you're not aware, Pyrite is a typewriter for Python. And Pyrite was inspired by the design of TypeScript. It improves on it in some ways, It doesn't improve it on some ways as well. And so I was actually felt really familiar when I stepped over the line right to the other side and I started working on stuff. And so I think my first bug fixes were like fixing something with omit, with like the helper type to do with like private properties and protected properties. That was one of the things. And then working on parser bugs. So I think one of the first parser bugs that took me like three PR iterations was the parsing of arrow functions mixed with conditional expressions mixed with type annotations where if you think about it it's like arrows but then there's also colons but there's also type annotations and it's like really ambiguous like what you're supposed to do with these and i that took a lot of time and it's been the same ever since i've modified it like three years ago and so i'm assuming it's correct now but i always get anxious when someone reports something or i saw i think i saw nicolo from babble post something about these conditional expressions i'm like oh oh my God, please don't make me fix this another time.

7:19Because I was such a pain the last time to get it correct. Just like you take one TypeScript expression, you shove it in a JavaScript, and it does something completely different than what you expect. You're like, ah, right, the languages are different, right? And so that was one of the first things that I fixed. And then soon after I worked on the whole module migration stuff, that was like pretty soon after I started on the team, actually. Like a couple of months in is when I said, hey, Ryan, can I work on that? And I took over the work and we switched the whole code base to modules, which was the first time that I modified every line in the code base, right?

7:54Let's pause there, actually. Not all of our listeners are deeply familiar, as you and I unfortunately are, with CommonJS versus ESM. When you say convert TypeTube to modules, first of all, what does that even mean? What's the context here? So back in the days, in the past, there was not ES modules. There was no specific syntax blessed by the committee that was like, here's what's in the language and this was you parse. And so there are lots of competing formats for modules out there. I'll put out some acronyms, AMD, system.js, blah, blah, blah. And the one that Node used was something called the common.js.

8:30I say did use, it still uses, called CommonJS, where you basically build your module, the file up, but you put all your exports onto one object, and that's what you export and what everyone else consumes, right? And that's CGS. CommonJS is like import, export the syntax written out. It's different, works differently, has different considerations. And it turns out that TypeScript used none of these. TypeScript predates ESM for sure. it predates many things. And so TypeScript was written in terms of namespaces, which, by the way, were never called namespaces at the start. They were called modules.

9:09And in fact, they were called internal modules. Internal modules meaning that you wrote your code inside of modules, which are namespace-y, kind of like C Sharp or something. And you wrote your code in those. And then the TypeScript compiler would just take all those things and jam them together into one file. And that was the output. It was like that for like a decade, something like that, like eight years or something. But what that meant was that we were stuck on old syntax. Things turned out to be a lot slower because of it. And we had no idea actually. And we wanted to change over to modules, which required a big changeover.

9:44We had to like change everything that was implicit into an explicit import, take all the code unindent it. We had to rewrite a whole bunch of stuff, make it work, then add a bundler because now we aren't using TypeScript to put everything together again, stuff like that. So that was basically the big transform that I had done in that step, which was multi-month process to finally one day run the script that does it because it was fully automated and just rip through it and then send a line, a PR that's like 3 million lines of code or something. Right. And it worked out. So I actually want to ask you a question on this.

10:16in the general context and framing of migrations of code or doing code mods and changes? Because there are a lot of teams out there who have changes like this, where their code base was written in year X with module or some style Y, and then X plus five or 10 or even 20 years later, Y is outdated and now they want to move it to Z. What are the kind of strategies or mental framings that you use when considering how to or whether to migrate a code base in that way? So step zero, the thing to consider the best is just, let's speak JavaScript. JavaScript is changing so much all the time. It's like, that's the thing, right?

10:52And so the best way to solve this is to be preemptive and like, unfortunately, keep up with it and like try to make modifications in time as fast as you can and keep up to date so that you don't have to do a big migration. But that's obviously not possible from everyone, right? You need to have people dedicated to doing that. And so I think that the most important thing is to try and write tooling to do it, because if you don't, you're going to have a really hard time. And so the migration that I did, that was entirely read using TS Morph, which is a project by David Sherratt that wraps around TypeScript and allows you to modify code and turn it from one step into another.

11:29And so I basically was able to automate every single step of the entire process. And then if TypeScript changes, I would rebase the code base on top of the old one. Right. And so the automation is really the reason that it was possible. The only way is to do brute force, which that works for me sometimes, but not when I had to redo the whole thing over and over and over again, trying to keep up with it. There's tons of interesting stuff inside that whole process, but I'm not sure you want the little tiny details of that whole process. There's a whole talk about that somewhere. I think there's a lot of utility and understanding, maybe the high level concepts.

12:02You mentioned TS morph, and because you work on TypeScript, you're well-equipped to answer. What does it mean to morph TS? Or I guess in this context, what is an AST? AST is abstract syntax tree. Every language has this. It's like, here's your code, it's parsed out, and it turns into a tree of like, okay, the file is the top node. And then all the different statements inside the file are the next nodes down the list. And then you set up those, you say, ah, well, this is an if statement. And then you walk down and you have more stuff inside of those. It's like, oh, here's the condition. Here's the body of the if statement.

12:35Here's a call to another function. Here's the name that you're calling. Here's the parameters for that call. Oh, those parameters, those are also calls. It's a big tree that goes downward. And so when you're trying to write code mods, TS, morph, all these different bits, transformations, everyone has a different name for the same thing. You are taking the AST and you're just turning it into something else. You're doing like a rewrite from one thing into a different thing and making the code work the way you want it to work. And this is such a powerful technique for application migrations, right?

13:04If you have whatever, thousands, hundreds of thousands of lines or files, there's no way you're going to be able to brute force a large migration such as CJS to ESM. This seems like the only real way to do it oftentimes. Depends how much resolve you have. But yes, I would say automation. Sometimes, you know, you spend so much time doing the automation, it's not worth it. But usually not. So you accomplished one of the very fun migrations of TypeScript from CJS to ESM. What were the benefits or what were the results of that? Well, the headlining thing was that the whole thing got 30 to 40 % faster.

13:37That comes down to really weird details to do with JavaScript. In short, because of those namespaces, everything was inside of an object. So if one file wanted to talk to another file's contents, it was actually a property access. It was doing a full object access to do those things. And so the entire time, even though everything looked like it was local, you didn't wrote those out by hand. You actually were spending 30 % of the time just doing that. And so we ran the transformation. And then I ran the code. I'm like, whoa, what the heck? This thing is way faster. That doesn't make any sense. Oh, wait, no.

14:11Actually, this makes a lot of sense. Crap. And so once we turned it into modules now, yes, they're separate files. They import each other. But a thing like ESBuild or Name Your Bundler can understand that. So when they put that into a single file, it rewrites all the references to reference things locally. And then the engine is just like, well, that's just a static lookup. That's right here in scope. And so that's really fast, right? So we gained a whole bunch of performance that way. So that's performance. That's what matters, I think, to the end user, right? But for us, it was kind of like, well, instead of running a full 30-second compile or something just to get an output JavaScript file, we could run an ES build and that took like 100 milliseconds right so now anytime we start our test it was like instant versus waiting you know 20 to 30 seconds to actually get it to start that and other tooling that we were able to use that we weren't able to use before because no one used namespaces except for us basically no one no one used the weird features that allowed tsc to merge the files together like tsc secretly was a bundler the whole time and no one actually use it except for us.

15:13And so we dropped that feature straight out of like 5.0 or something because we're like, yeah, no, this is an anti-goal for us. We only preserved it for our own use. And now we absolutely do not. We need it, right? This portends things to come in two ways. One, the native code speedup and also the improvements to TypeScript internally enabling end user benefits such as performance, such as dropping deprecated features. But I want to switch topics ever so slightly for a bit before we go back to TypeScript, because TypeScript isn't the only large repo managed by the TypeScript team. What is definitely typed?

15:45Definitely typed is a collection of type definitions for libraries that don't have them. So if you npm install, I don't know, React, great package, right? It doesn't include any type definitions at all. TypeScript cannot read that and go, oh yeah, there's an export called use state, right? It doesn't have that ability. It can't analyze into the JavaScript code, look past their bundling and midification to figure that out. And if it did, it wouldn't really be very useful. If React were written in TypeScript, they would emit DTS files and they'd have it, but they're not written in TypeScript, right?

16:21And so definitely typed contains like some 8 ,000 packages worth of declarations that say, hey, this package exists. It has these exports. They have these types. And this is how you can use them, right? So when you install at type slash react, suddenly you have all the types that make React work. And so you can say import React. and now you are off to the races, right? You can see everything in there. And how is this set up so that the packages are defined and then published? Well, since its inception, which is, again, also 10 years ago, it was like thousands of individual folders with TS configs and basically a script that would scan them and see if anything changed and then package them up and publish them off to NPM.

17:09I'm assuming what you're getting at here is the new form that I introduced maybe a year or two ago, which is maybe more familiar to people that have been worked around in JavaScript. And so instead of having a whole bunch of loose things with like a couple of package JSON files and then like really weird TS config options to sort of map them together, which then broke things in other weird, subtle ways. I made an effort to convert the entire thing to a PNPM monorepo. And so now all the packages link to each other as though they're actual packages, right? And so you PMPM install and it takes a while in the current state, but you'll link 8 ,000 packages together or whatever subset you want.

17:49And so now they're all linking to each other, declaring dependencies properly. We used to scan the files and figure out like, well, you mentioned Node, so we're going to put Node as a dependency of you, even though that maybe wasn't required at all. And so the new form is basically a bunch of packages. And then we take out the files that we want to publish, declaration files, put everything else behind, generate a package and publish it up to NPM whenever it changes. Let's pause there a little bit. I'd like to go through a similar exercise as the migration before. Let's say that I'm on a team that has a large existing app that's not set up as a strict modern monorepo.

18:22And let's say that I really did want to migrate it over. What are the kind of techniques or tips you would give me in trying to migrate my existing app to a monorepo? I think it really depends. The main thing is that it depends on your repo layout. There's a lot of people that have what is effectively a monorepo, but it's not broken apart strictly. And so they have imports that are like relative paths that are really long. And they're actually supposed to split them out. You can want to split them out into different packages, right? Right. And so if you have the structure of different folders, you can create package JSON files in there.

18:54And then most of the package manager out there are totally fine figuring out where to find those things and map them together. I'll use PMPM as an example since that's what DT does. You just make package JSON files and you put them in your glob and then it finds them and puts them together. And the real challenge is just breaking apart things so that the imports are no longer relative to somewhere else. You're actually working in a world where all their packages are kind of like they exist on npm and they're already there and so you want to refer to everything by their public names because that's what people also let people are going to you know import them as or if it's an internal app it doesn't matter quite as much but now you can split up your packages into multiple pieces build only certain parts of them and that's like a whole different monorepo setup configuration thing with typescripts or something right but splitting them up and let you declare the dependencies and you can better see what's and used by different parts of your application.

19:44It's mainly the big transform is just the import stuff. That's the hardest bit, right? If you get them in the right folders as is, you can pretty much figure it out. And for TypeScript, that's a different thing where like we can pretty much figure it out no matter what you're doing, as long as you have the configuration file set up. So we're happy to do that. But there's like a whole bunch of stuff talked about there in terms of like project references and bits and bobs, but not sure what. Can we actually talk about that? Could you give us a primer what are TypeScript project references since you bring it up?

20:13Sure. So in TypeScript, everything is in a project. So we'll start off with that. You make a TS config, you say, hey, here's the files in this project. When you call TSC with no arguments, it automatically finds TS config.json, but you can pass a flag that says, here's the project. And so it used to be that you'd have TS configs, you'd build them. If you split your program apart, you could do that. but it sort of doesn't scale really well for like, I want to modify one part of my repo and then not rebuild all the other ones at the same time. And so a while ago, project references were added to TypeScript where you can split your application up into different blocks that define like, okay, here is the front end, which depends on the common bit or like, here's my application.

21:06It might depend on the component library, but also the API types. And also those can be different bits and pieces across where when I rebuild my actual front end, I don't need to rebuild all the stuff to do with the API. I mean, that's just always there, right? Or maybe I don't need to rebuild the components if I'm just really building the main front end or something. And so references allow you to split up your code into multiple pieces that declare different sets of files. And then you can say TSC-B, so build mode, and then it will remember, oh, well, this DSConfig doesn't need to be updated.

21:39It already built it and it will just skip it. And so that's a speedup in one way, but also it allows TypeScript to figure out like, oh, when you go to def on something, how do I map that to the actual source file and not declaration output files or something? It's all about like granularity and sort of editor use makes things better. Although there's always a limit where like some people will try to make like 2000 project references and then you have a real problem because it doesn't scale that well that way direction. but they're pretty good for breaking apart your code base into different bits and pieces.

22:09Yeah, when people think of TypeScript performance, very often they think of the type system because it's incredibly rich. Someone got Doom running in it. Congratulations again to Dimitri from Michigan. But really, another aspect of TypeScript performance is splitting things up and setting up your project references so that it only has to rebuild some of the application parts that have changed when you save. I'm curious, do you find in production that when people come to you with a team with performance issues, it tends to be, let's say, more in the type system or more with the project configuration side of things?

22:38Honestly, it's mostly configuration. There are people out there who have real type performance problems, whether or not they are just doing something wrong or if they're intentionally trying to do something that is really bad for performance. Lots of really crazy type libraries out there that try to parse everything out of a string or something like that, which don't work very well in terms of performance. sometimes. But most of the time, it's kind of like, oh, whoops, I accidentally didn't configure the types property of my tsconfig. And therefore, it tried to load 1000 at types packages, because unfortunately, the default behavior of TypeScript is to load all those by default.

23:17And like, oops, that fixed like 90 % of our problem. That's a real example that happened. I'm talking to a team about that. There's other places where it's like, we have one project, and it's massive and we just compile with once. Oh, you should probably try using references and see if that helps because it makes things incremental. There's other teams that they have gone so far with references, they have 2 ,000 of them. And so now the fixed cost of having a reference is the dominator on the amount of time you're taking. And so it's like, maybe have fewer projects. Do you really need one TS config per React component?

23:53No, you don't need to do that hard. It's usually stuff like that or they'll misconfigure stuff with like paths or they'll have a big paths array with like path remappings. That's like a hundred long lines long. And then we're like, oh man, we never thought anyone would ever have a hundred of these things. And so the code base is just this linear loop that loops over everything, trying to find them for every single file. Right. And so it's like, oops, did I make a little N squared or whatever? Then, you know, whatever terrible algorithm, oops, that wasn't intentional. Right. Let's like push it on us, but also like, well, maybe don't use paths or don't use the remappings or something.

24:27Like there's other better features to that same thing. A lot of the cases are just like the TS configs were completely different between all of our projects and therefore types couldn't reuse ASTs. Whoops. Didn't mean to do that. Like that's not good. Okay. We shouldn't even them out. Use a, you know, a shared base config or something between some of our projects to help with that. Other bits, like there's lots of, there's lots of stuff. Like this isn't a big contributor, but people will set their target to like ES5. Okay, so you're just spending a whole bunch of your mid-time transforming your code into term of iterators or something.

Read the full transcript

24:58Or like ASIC await. Yeah, it's 2025. Maybe consider raising it because everything ever can run better stuff. That's a minuscule portion, but there's lots of little paper cuts, right? Where it just keeps coming. It just keeps coming, right? When we talk about TypeScript performance, there is, of course, the massive gopher in the room switching. And I feel viewers would rebel if we didn't address it soon. So Jake, please tell us what's going on with TypeScript in Go. So for the past six months, we have been porting TypeScript over to a new language. So TypeScript is written in TypeScript. And we were hitting some performance walls that like, it doesn't seem it's likely they're going to be fixed in like a short period of time, or they may be just inherent to the engine and just how the language works.

25:44And we were like, okay, everyone wants us to read everything in a different language. Okay, well, we should try out and try porting some stuff over and see how it goes. And we did lots of trial and error, you know, trying different languages out. And so we ended up in a position where we ported all of our code over to Go. And so we published, I think, what, two days ago, the big announcement of in the repo that has pretty much the entire checker ported. A lot of emit ported. Obviously, parsing and binding is ported. A lot of the CLI is ported. We have a language server implementation that does a couple things.

26:21But the biggest thing is just that through the port, through us using concurrency, parallelism, different perf tricks that were available to us in native code, we now have a TypeScript, which is seemingly, I say seemingly, it is 10 times faster than just running TSC straight up. And there's people that they tested it on day of, and they're like, hey, my company has this 3.5 million line code base. It takes us seven minutes to build our code. and now it builds in 30 seconds. And we're like, aha, that's a good speed up, right? Someone else was like, I have a 30 minute build, which what the heck, but a 30 minute build and now it's only a couple of like few minutes, like it's like seven minutes or something.

26:58Well, that's pretty good. I mean, 30 minutes to seven minutes is incredible, but also what the heck are you doing? You have a 30 minute build, but I've seen projects. I have my personal project on the side where it's like, I've been testing on them just to see what it looks like. And it can do the full compile from end to end, parse, bind, check the whole thing, emit all the files. in less time than it takes our current TypeScript compiler to run the help command. It's pretty insane. It's pretty great. And I'm having a great time working on it. So that's incredible. 10 times faster. Just think of the CI builds that are going to be reduced by people spending less machine time running on this.

27:33Oh, yeah. And I think most of all, we've talked about end to end time. How often do you run a build? You know, not actually, honestly, most of the time in the world on TypeScript is not spent running a build. It's in the editor, right? And so there's repos out there like VS Code where it takes 20 seconds when you open up to the VS Code repo to load their code before we actually able to start giving you like hovers. And because we're in native code, because we're doing parallelism, we are massively concurrent, like parsing out files and everything. And so now that thing loads a couple seconds tops, right?

28:08That's like a big deal. We have people that it takes them like a 30 second or a minute just for their editor to start, like on ridiculously sized projects, like giant monorepos. And if we can do the same thing in a few seconds, that's a big deal. You can start opening up your editor and actually get feedback instantly. That's pretty good. You know, yes, checking, it's faster. Obviously, emitting is faster. But it's pretty great to actually be able to load your code in the first place. That's one of the biggest things. I think that's in the blog post is like one of the first things we mentioned.

28:34Now, there are some FAQs that have been popping up a lot. And there are great answers already in previous interviews and the live streams in the discussions on the new repo. But for the sake of completeness, I'd like to ask you some of the common ones now just to get the high level overviews. Why can't you just make JavaScript faster? Why can't we just make JavaScript faster? First off, they are making JavaScript faster. There's lots of proposals out and people working on things that will make the language faster and add certain features that could enable people to write faster code inside of JavaScript.

29:09there are just some things about the language itself which are inherent. And I don't like this is the design choice, right? But like one of the things that JavaScript has is that there is concurrency, async await, right? But in JavaScript, you're only doing one thing at a time. You're switching between maybe multiple tasks if you're using async await, but you're only doing one thing at a time. And so if we wanted to write a parser that's fully parallel, we can spawn up a bunch of like web workers or something to like parse a bunch of files at once. but all of those ASTs are often different threads.

29:41And so we can't actually talk to other threads directly. And so we'd have to pull that data into one runtime and like then use it. So like we can't make parsing parallel. If you're in a native language where you have shared memory concurrency, which is like the big phrase, that's many languages out there, then you are able to parse in parallel and actually get all the results out, right? Right. And so like that, JavaScript is there's proposals working on to do like shared structs. There's shared array buffers. Right. Those are ways to share memory. But none of them are quite exactly the kind of thing that you would want to just like massively parse a whole bunch of stuff in parallel and access it directly.

30:25All of them require some sort of serialization kind of, you know, shared structs, I think, is the most likely to one to actually help with that kind of a thing. But it's not here and people are loading. Unfortunately, it is not here for years till it is. Right. And that comes down to engine optimizations and how that's going to work out. So, okay. You mentioned quite a few other languages. The last couple of years, everyone has been seemingly writing all the new projects in Rust or the rewrites in Rust. You are not writing in Rust. Why go over Rust? This is going to be a long list. I'll preface it by saying I really wanted Rust to work.

31:00I tried really hard to prototype stuff. I think we all wanted to make something work, right? And there's lots of challenges with Rust. There's the obvious ones that people think about immediately of like, I have to do the borrow checker now. Okay, you have to build the borrow checker, yeah. That's inherent to the language, right? Which adds an element of friction. But there are some fundamental things that are really challenging if you're working in Rust, which would really hamper our progress in trying to port code. And that's the main thing is that we were trying to port the code. So all in all, TypeScript is a language without like a raw, like a specific specification of like how it works.

31:38And so if we don't take this code and we don't port it one to one, it will behave differently. And then some project will break and we'll be like, oh, crap. We don't know how to fix that because our structure is completely different and broken in some different way. Right. And so we wanted to port. That was the main thing. Right. The prospect of like one to one side by side, having exactly the same code for both of them. didn't seem like it was very possible using Rust. And that comes down to stuff like cyclic data structures. So our ASTs, we mentioned before, our ASTs have things called parent pointers, where you can walk down the tree and then look up and then walk back up the tree.

32:16You can go up and around, right? And so that's a challenge. That's technically solvable. The Dino AST has a way to map those things by basically duplicating the AST a second time so you have parent pointers. But it extends further from that because you'll have like an AST with symbols. And those symbols will point to other symbols and those will point back to other declarations. And so you have multiple files that have like multiple declarations. And then you're in the checker and now you're building a type and the type is recursive. And okay, so now the type needs to reference itself. And so it's like, there are absolutely ways that you can tease out a different representation entirely and how to re-implement these things.

32:56But it would fundamentally be like a re-implementation. And so the behavior would probably change in ways that we don't know how it would go. But also, it would take us a really long time, I think, to suss out all those details and get it complete. And so that really guided the way that we chose the language and prototype stuff. Sure. One last FAQ on this area. Anders also was a big designer and leader creator of C Sharp. Quite a few Microsoft and.NET area folks were surprised, perhaps more than surprised, that C Sharp was not the language. Why not C Sharp? C Sharp is great. We have no problem with C Sharp.

33:35We love C Sharp. Obviously, Anders made C Sharp. There's no question about that, period. There's so much code at Microsoft that C Sharp is a whole bunch of great people working on that kind of thing. Absolutely. I think it just comes down to specific language details. And so I'll give an example. TypeScript is written synchronously. We actually don't have any async await at all in the entire thing. Maybe at the fringes to do communication with an editor or something, but it's all synchronous. And so if we wanted to make our code concurrent, how would we go across that? How would we approach that?

34:12In C Sharp, the way to gain concurrency is to use async await. This is the same for... JavaScript has async await, I think, because C Sharp had async await. right and so our code is written synchronously but to put it in async await code it'd be like a very different kind of transformation in go like the concurrency model is completely different where you write your code look it looks synchronous but you can be preempted and so you sort of gain the concurrency for free just by orchestrating your code in a different matter right and so you know porting the code in one-to-one like that is like a little bit different and may not have worked as well as we might have expected it to work.

34:49That's a language example. There are other things like Nick Anders talks about the differences in the way that structs work. In the Go code base, we have lots of self-pointers. So we have self-interior pointers. So we take the address of a random property inside of a struct and you're able to do that. I'm not sure that C Sharp was able to do something like that. That could be changed in C Sharp, of course. But fundamentally, like C sharp their object model is different there's lots of differences and i don't know if i could list out all the different positives and negatives for this is obviously positives like in c sharp it's obviously positives and go for in other aspects right it's a fascinating study into even though a team might be more familiar with a particular language the microsoft folks are generally quite familiar with c sharp the project itself is fundamentally not built for that paradigm It's a relatively lower level target.

35:39It's a compiler. It's a low level framework and area that just so happens to be quite well suited to Go. I'd say that's true. C Sharp certainly has lots of AOT work going on as well. They're pretty different. And I think that there's also the aspect of Go is a somewhat established player instead of JavaScript because of ESBuild, right? Rust is a big thing. Go is less of a big thing, but ESBuild is written in that. And so that's sort of also an important factor in how we choose a language, right? Sure. Now that we've decided that you were correct to choose Go and no one should be yelling on the internet about this, I want to talk about the transition a bit.

36:19Because you've mentioned you like doing large transitions at scale with semi-automated tools. How has that transition been implemented internally? I mean, it's been going pretty well. Like there's a tool that allows you to take the code from the types of code base, syntactically transform it into Go, and then you're able to copy and paste functions at a time. And they're mostly correct. They look about the same. And then you just fix up the data structures so that they match what the actual implementation was. Why not use AI? I tried AI. It works kind of. I think it's really a challenge because of like The amount of training data out there on compilers written in Go is limited to very few, and especially training on code that is the TypeScript compiler.

37:06And so it works pretty well if you like. I definitely side-by-sided the code in my editor with Copilot. And because it gives both files as context or something, it sort of figured out what I was doing, and that helped me port some code, absolutely. This was also like six months ago, right? And things are always changing. and the syntactic form was like the easiest way to get there in my opinion at least like to actually transform the stuff raw one-to-one. There's like tons of little tiny special cases that happen in our code base only. It wouldn't work elsewhere. The tool is not for people to use at all.

37:41It's sort of like an example. The code is really bad, right? But it works. You said this code is open source, TS2Go on your GitHub? Yes, but don't look in the box too much. Understood. it. It's a really long script with lots of little special cases that transforms the whole thing from one to the other using TS Morph to walk the thing. Although it doesn't output using TS Morph, since obviously it's ready to go code. Let's say yet again that I am a general team who has a similar problem where I have a code base in one style or framework or language and want to output a similar or equivalent code base in another style or framework language.

38:19Are there any general tips or tricks you'd suggest that I look into before I embark on that journey? Well, the first step is to think if you can not do that. I don't know if I would wish this on anyone. It's like a big deal to change from one entire language into a different type of language. And so my first suggestion would be there are lots of performance tools out there to help you find things instead of languages that you're already in. So avoid if you possibly can. I think that it comes down to sort of like, are you able to port code? incrementally. So like if you're using JavaScript and you want to write Rust, for example, there's lots of tools out there to allow you to like piecemeal transform code bit by bit using like NAPI RS or something, right?

39:02That's one mechanism to do it. Now, is there an easy syntactic transform that you can make in that? I don't think that there really is. JavaScript is very different than a lot of other languages. And so many things that are possible in other languages are pretty difficult for like say javascript right and so the transform that we made for like javascript to go sure it's like automated kind of but it required a lot of thinking about how to structure things and how to fix things and go ah we need nil checks here and like how to like update data structures to be like the right format and add the visitors and all the different bits and pieces and so that kind of transform is really challenging i'll say javascript between native languages is a little bit less scary because you don't have to worry about like, oh, JavaScript has optional properties.

39:47What language or compiled language has optional properties? Like none of them. That's not how it works. Memory is laid out in a specific way. You need to put the things there or you don't. It's more challenging to like deal with going from an interpreted language like JavaScript to something else. Between native languages, that's much more reasonable because you already sort of laid things out already in memory. That's actually an interesting point. First, TypeScript back to it specifically, there are optional properties in the TypeScript languages, internal and external representations of, say, AST nodes or options types.

40:21How does that work when you transform it over to Go? There's a couple methods. You can either make different structs entirely for the different data structures. So like this thing has something, this one doesn't. And then you can implement like an interface or something to distinguish between them. Go doesn't have unions, so it's really difficult to put those things in the same box. but most of the time you just end up with a field that's actually real there and it's just nil it's like null or something like that right so it's like spending the memory and it's interesting because like javascript is faster if you do it that way because then the runtime can understand like produce the same code for both cases and you get faster right and those are transforms that we made in typescript like a while ago as well to like fill out all the objects in identical formats even if they contain undefined as properties because the engines like that better because people don't really want to deal with multiple different kinds of objects with different properties on them or not on them.

41:13The runtimes really like code to be like really even with the same objects, with the same data, the same offsets inside of objects. Inside the Go code base, it's kind of just like if things are optional, there'll be a pointer. And sometimes maybe it's like there's three things that all are set together or not set at all. Well, you just make another struct for that thing and you just make a point of that struct instead, right? That's sort of been the strategy for those. It's interesting that so few JavaScript projects have to deal with that kind of data normalization, avoiding the polymorphism in that way, that it almost feels like a hint that, hey, if you're a JavaScript project dealing with that, perhaps you are more better represented as a Go or other lower level language project.

41:51Yeah, depending for sure. Most applications, this doesn't matter for it all. It's just that obviously we're writing a compiler, We are extremely CPU bound and we want to go as fast as we possibly can because it matters to a lot of people. Right. I think it's a little bit more forgiving if you're working in a browser where you're waiting for a render to happen or you're working on like a server where it's like, oh, yeah, I really optimized this thing. But then I waited 100 milliseconds for Postgres. It's kind of like, well, you know, how much did you really achieve on that front? Right. It's really difficult.

42:24Like we're in a bad position to try to write a CPU powered, like a really CPU heavy piece of code. We don't have too much time left, but I want to spend most of the rest of it talking about what you think is coming up next. Let's say that we got TypeScript into Go. It all works. Everyone's happy. 10x performance boost. Have you started thinking about what the implications of that are or what's coming after? I'm really focused on making it happen. So past that, I don't really know. We have lots of plans on the horizon of getting it into Wasm because it's important for the browser. I mean, that's part of the job already.

42:58So maybe that's not something in the future per se, but like the other thing that people are talking about is like, oh, well, you're faster. So you can do more stuff. Right. And so like, can you add this feature? Can you add that feature? It's like, maybe there's some features that we are thinking about for sure. But like, it's sort of like induced demand is the phrase that I've heard. If you make it four times faster, people will start doing four times more things than them. And then you're back to the square one where you were. And so I don't know what all we're going to add or what all we're not going to add, but there's some stuff I think that may occur.

43:30I think a lot of the time it's just going to be spent getting it right because there's just so many users out there who need lots of different things. And I think we're getting the core stuff really well done. But there's lots of stuff out there like dealing with the API, dealing with the editor integration, dealing with browser stuff that has yet to be seen how it's going to progress. But we're pretty optimistic about getting that stuff done well. There are a lot of open source projects out there who are waiting with bated breath to be able to use native speed type information. Oh, really? I wonder who.

44:03Well, that's great. Jake, I have no more technical questions for you, but just one or two left. I'm going to ask you a question and you're going to correct me. What do you think is the greatest Weird Al Yankovic song? Yankovic. I feel like it's like Yankovic is when it's the year 2006 and you're downloading a song off LimeWire or something, right? They've no spelled the name. But I have to choose Albuquerque, right? You got to choose Albuquerque. Why? I don't know if I can explain that. It's so long. It's got lots of lyrics to get to memorize. It's just a good one. I don't know. That's a good one.

44:37What for you defines a good Weird Al Yankovic song? Or rather, what for you is the appeal of Weird Al Yankovic? what's the appeal oh god i don't even know what i'd say what makes a good song is what i don't know the original song at all if the entire thing has been wiped from my brain because that's his is better you know there you go right oh that's that's more memorable for me for me the original songs are buries and original obviously it's not it's not that's not a parody of something so you know well jake you've been a trooper thank you so much for for hanging out tolerating the weird Yankovic question and diving so much into the world of TypeScript.

45:13We talked about how you got started, what TypeScript looked like internally before you got around to switching to modules, and now as part of the big migration, switching to Go. There's all sorts of great stuff happening, and it's really exciting to be a web developer these days. Last question, if there was anywhere on the internet you'd want people to go to find out more about you, your work, TypeScript, or the URLs you'd suggest they look into? Jakebilly.dev. That's the main thing. It links to everything else. It's also the same username on Blue Sky if you want to see me there. That links to everything.

45:42So if you go there, you'll find everything else. My GitHub, everything else. It's all Jake Bailey, like one word. Excellent. Well, thanks so much, Jake. This has been fantastic. So for Software Engineering Daily, Jake Bailey and Josh Goldberg, thanks for listening, everyone. Cheers. Cheers.

46:07You

From the publisher

TypeScript is a statically typed superset of JavaScript that adds optional type annotations and modern language features to improve developer productivity and code safety. The TypeScript compiler performs type checking at compile time, catching errors before code is run, and also transforms TypeScript code into clean, standards-compliant JavaScript. Jake Bailey is Senior Software Engineer at

The post TypeScript with Jake Bailey appeared first on Software Engineering Daily.

More from Software Engineering Daily

All 195 episodes
TypeScript with Jake BaileySoftware Engineering Daily · 46 min
Listen in VO