Now, what does this actually mean? So, for example, on a laptop with 12 cores, which is what we see here in this picture, we only use some of that computing power. We can see that even while the build runs, there's a lot of CPU power that is still being left unutilized. A lot of CPU cores that are just sitting there idle. So, that's definitely not a great start for running things in parallel.
Let's see sometimes what kind of improvements could we get if we did this? And the answer is that we definitely will get improvements, but they're just not that great. I mean, there's about a 10-20% improvement that we get from running things in parallel using this approach, which is again better than what we had, but it's not something that is going to be dramatic.
So, how can we increase the parallelism available? How can we run more things in parallel? Well, for that, we first of all need to understand exactly what it is TypeScript actually does, and what it does is three things. It does type checking, it does declaration emit, and it does JavaScript emit. Now, these things are not perfectly independent, namely declaration emit depends on the result of type checking. But for each one of our projects, TypeScript will do all of these three things. So, inside the build for each of our projects, all of these three things have to happen.
Now, there is one key insight here, namely that what is needed to unblock a project from starting its type checking phase is that it needs to have available all of the declarations for its dependencies. So, declaration emit is what is actually needed for the dependencies. We don't really care if the dependency has finished type checking if we can get its declarations. So, the actual dependency queue would look more like this, right? Each type checking phase depends on the declaration emit of its dependencies, not necessarily the type checking. That's an interesting insight, but as long as we still have this dependency between type checking and declaration emit, the fact that this is the case, the fact that we depend on the declaration emit doesn't really help us because we need to do the type checking anyway.
Could we remove this dependency? Well, for that, we should first of all look at why JavaScript emit is so independent from type checking. How is that? We actually even have tools that do JavaScript emit without the need for a type checker. They do it completely independently of TypeScript. How is this enabled? Well, a few years back, TypeScript added a new mode to TypeScript called isolated modules. So, what exactly does isolated modules do? Well, it ensures that each file can be transpiled from TypeScript to JavaScript individually. It basically removes any dependency on type checking from JavaScript emit. So this means that JavaScript emit becomes a purely syntactic process. Tools still need to understand TypeScript syntax. So, every time we get new syntax in TypeScript, all tools that do JavaScript emit need to understand this new syntax. But the advantage is that they don't actually need to understand all the semantic rules of TypeScript. They just need to understand the syntax enough to be able to remove it. So, basically, when we do JavaScript emit, we start out with a TypeScript file, and what happens inside a JavaScript emitter is that all the type annotations are removed, right? And this is a very simple process. It's not hard to build such a transformation. At least it's not hard compared to actually building a full typechecker.
Comments