Configuring TypeScript 16 exercises
explainer

Understanding Isolated Modules in TypeScript

TypeScript has evolved over time to support changes in the JavaScript ecosystem. One of the significant changes was the addition of imports and exports to JavaScript, which required TypeScript to adapt its behavior.

One such adjustment was with the TypeScript introduced the isolatedModules option

Loading explainer

Transcript

00:00 TypeScript has been around for a long time, and it's been around so long that it's had to change its behavior and its config a few times to support changes in the ecosystem. One of those big changes was imports and exports. That's right, TypeScript is older than imports and exports in JavaScript.

00:18 What happened was TypeScript had some behaviors that are slightly incompatible with imports and exports. Let me explain what I mean. Now, the isolated modules true option basically disables some TypeScript features, which would be unsafe in an import-export environment.

00:37 Now, what do I mean by that? We have a declare const enum here. Declare puts the const enum in an ambient context, which basically means that this disappears at runtime, like this const enum does not exist. Numbers.0 is supposed to be just inline, supposed to be just zero like this.

00:55 But if we look at the compiled JavaScript code, index.js here, what we end up with is example equals numbers.0. Numbers is not actually being erased, or rather it doesn't exist in the JavaScript here. This is actually a runtime error. Now, what's happening here is that we can look at this,

01:14 cannot access ambient const enums when isolated modules is enabled. What this is doing is it's disabling this ability, disabling the ability to declare a const enum. And then if I actually revert this and say, this is actually just a const enum, now it's going to work.

01:32 Now, when we look at the JavaScript here, numbers is actually defined. But when I had declare in this, then it actually doesn't get defined. And it's just literally numbers.0, which is a runtime error. So the reason that isolated modules disables this behavior is because this can only be compiled by TypeScript.

01:51 It can only be compiled by something that understands the whole type system. If you're using something like ES build, SWC, or Babel, then they don't actually understand the entire environment that your code is executing in. They do something called single file transpilation,

02:08 where they just look at a single file and then transpile it. This often means they're much faster than TypeScript because they don't need to type check the whole thing before they can compile it. They can just go and just go through single files and transpile them. But the issue with a declare const enum is that it could leak out of this file and into the global scope,

02:28 and then single file transpilation doesn't work. And so isolated modules, what it does is it basically says, I see, you want to enable single file transpilation. You want to say, okay, other things than TypeScript can transpile my code. And you want to say, I'm operating in like a module-based system.

02:47 So isolated modules is a really great default because, first of all, often you are going to want things other than TypeScript to transpile your code. And the things that it disables are really like, it doesn't disable much behavior, honestly. And it just gives you an extra little bit of security so that your code is more portable between different systems

03:07 if you need to move it around. Because this declare const enum anyway, it's a little bit funky. And actually the TypeScript docs recommend that you don't do it anyway. So isolated modules, really, really sensible default, means that you won't get caught out if you move bundlers or anything like that. And just very, very sensible default.