Configuring TypeScript 16 exercises

Organizing TypeScript Configurations with Project References

There are several different ways to organize TypeScript configurations. Let's look at a few to see what's possible.

Solution 1

In this solution, we have a new tsconfig.json file that has references to src/client/tsconfig.json and src/server/tsconfig.json. Unfortunately, there's no way to

Loading solution


00:00 So, there are actually several solutions here because I want to show what's possible with project references in terms of organizing all the tsconfigs they spawn. First of all, we have a new tsconfig.json file that has references to source client tsconfig.json and source server tsconfig.json. There's no way to do a wildcard in here,

00:19 so we can't say like source wildcard tsconfig.json. That syntax just doesn't work, although I wish they'd add it. And then we also have this files empty array here. The reason we have the files empty array here is so that we say, okay, this tsconfig.json, the one in the root,

00:36 is not responsible for actually type checking any files. All it's going to be used for is as a reference tsconfig.json, what they weirdly call a solution tsconfig.json, which is a bit of .NET language, in order to basically use these references to say, okay, first of all, run the client tsconfig,

00:54 then run the server tsconfig. Okay, on from there, we then take a look inside the client and server, and actually nothing needs to change inside here. We're still extending the tsconfig.json, but when we run our script now, first of all, we need to make sure

01:11 that we're running hyphen b here. Now hyphen b, what this does is it runs TypeScript in build mode. In other words, by running TypeScript, tsc hyphen b hyphen watch, what we're saying is run tsc here with a type tsconfig.json that's in this directory, and then run it in build mode.

01:30 And when you run in build mode, you run all of the references too. So this is the only way, if we don't do this, if we just say tsc watch, then it's not going to go through the tree and look at all the project references there. So by doing this, essentially what we get is type checking on the entire repo with a single command.

01:49 So we're running it, and if we change something inside the index.ts up here, then we're going to get an error here. Or at least we should, let me just double check that again. Check it's running the right file. Yeah, there we go. So again, we check, we go document, and we get a file change detected. Beautiful, working nicely. So we're getting errors across our entire project

02:09 just from a single command. But there's one thing we need to add in here actually, or we need to think about, which is in our tsconfig.base.json, we've added the composite true property. So this means that this enables constraints, as it says here, to allow a TypeScript project to be used with project references. In other words, the client and server are now constrained

02:28 to be using composite true. In other words, they add some sort of, it basically tells TypeScript that this is a child project. It's not, it basically needs to be run as a sort of run with project references. There's one more thing too. When TypeScript runs in build mode,

02:46 it also emits these tsbuildinfo files here. These tsbuildinfo files are big files, and they're not supposed to be committed to GitHub. So I think somewhere in here, possibly in my root gitignore, I have a asterisk tsbuildinfo to ignore these files. And when it does this, this basically saves the result

03:06 of the type checking for this project or for this little tsconfig. This means that when I run it again, it's going to be lightning fast. Boom, straight away, almost done, because I've not changed anything inside the client index.ts file. So this is really useful when, because it's caching the results of my type checks.

03:25 So project references are a superb way of coordinating type checks across an entire repo. This means you run one command in the root. It caches the result of various things, means that you end up with these tsbuildinfo files, which you can gitignore and get out of the way. And it means that you can just run a single command to type check everything.

03:45 But you might think, oh, this is a lot of tsconfigs. We've got two tsconfigs in the root and a tsconfig in both of these packages here. This is really annoying. Well, what you can do is you can move these all to the root if you want to. You can have four tsconfigs in the root, where you say, first of all, inside this tsconfig clients here,

04:04 we can say extends tsconfigbase.json. We get the same compiler options in here, and we can say include source clients. So now inside here, the client actually gets to not have a tsconfig inside it, and the root is where that tsconfig lives. The same is true for the server here.

04:22 And so we can say include source server. And now inside tsconfigbase.json, tsconfig.json, we now just reference the paths inside here, and it works the same way. This means you can't get confused by running something sort of inside a folder and thinking, why isn't this checking the whole repo?

04:39 Now there's only one tsconfig.json in the entire whole thing, and it's basically referencing this client and server. But then you think, oh my God, I've ended up with four tsconfigs in my root. Can't I move these into like a configuration folder? You absolutely can. So in this third solution here, we have a .config folder,

04:59 which is starting to become like a pattern for where people keep their configuration files. And we have a single tsconfig inside here, and it references path..config, tsconfig.client.json. Inside here, we're saying include upper directory source client. So you start to see how these things come together.

05:17 Now, all of our config for our entire project, even though it's relatively complex, just lives almost outside of our source code, lives just in here. And this means that we can just get on with coding our day-to-day stuff. We have a single tsconfig. It's all pretty clear how it's referencing, how it's working, and that gets to be separate from our source code. So if I was making any of these choices,

05:37 I would probably either choose the first one or the third one. This seems pretty nice, because it's also very clear when we look at this first solution here, that sure, the tsconfig.json lives inside the client, and so it must belong to the client. That makes sense. But whatever one you choose makes sense.

05:56 I think project references are extremely powerful.