Check out a free preview of the full Enterprise TypeScript course:
The "Type Acquisitions" Lesson is part of the full, Enterprise TypeScript course featured in this preview video. Here's what you'd learn in this lesson:

Mike explains where TypeScript looks for type declarations, such as the top level, type roots, explicit module declarations, and custom type roots. Prioritization of file types is discussed, and the importance of publishing accurate declaration files for libraries is emphasised.

Get Unlimited Access Now

Transcript from the "Type Acquisitions" Lesson

[00:00:00]
>> All right, type acquisition. So this is an interesting concept where, how do we find the right types for a library? We already dealt with this in one place, do you remember? When we pointed our tests for the chat standard library that we made, and we said, I want to use that specific declaration file.

[00:00:23] So we were jumping in at the top level of type acquisition. Top level meaning it's the first place type script looks. It checks there first and if it finds types, that match what it's looking for, doesn't bother looking anywhere else. And it's nice and convenient that there's sort of a very accessible place like a developer overridable place where you can just say, don't look in the node modules folder, don't look anywhere else, here's what I want you to use for this thing.

[00:00:59] So if it doesn't find something in your paths object in your tsconfig, it'll look at type roots. So this is another thing that you could put if you wanted to in your tsconfig. You could do this, and you could provide a bunch of different things in here. Copilot is spoiling my surprise here.

[00:01:21] The typeRoot that is in there by default is in your node modules folder at types, so it's definitely typed. And this tells you why we can import a module like prop types, right? That's a package that you use with React sometimes or just React, right? You might wonder, like, how does TypeScript find that apt types folder?

[00:01:45] Well, it treats it almost like a root folder here, right? It treats at types like a root folder, and then the sub folder within apt types. That's where it looks for the package name like React, or React DOM, or jQuery, or whatever it is. You could add more typeRoots if you wanted.

[00:02:05] And that would be another place that TypeScript would look up to try to acquire the right type declarations to match a given import. And this is just for types, right? This is not where we're looking like node modules and node type module resolution, that's still where we find the code to run.

[00:02:25] We're strictly talking about finding type information. The next thing down is explicit module declarations. So this, This would be like, in one of your TypeScript files you have declare a module or in a declaration file you have declared module. This is less common to see although we looked at an example in the intermediate TypeScript course, which I call the type registry pattern, which involved module declarations.

[00:03:00] But that is the third thing here. And then finally, I mean, this is really a type root thing, but it'll look for custom type roots, and then finally it falls back to the default type root here. If you want, you can use --traceResolution when running TSC, and it will tell you.

[00:03:22] It'll print like almost debug information, where it's looking for types and it didn't find it there. And so it's moving on to this next place and like up, I found something here and I'm gonna use these types. This is super helpful in cases where you're not getting what you thought you would get.

[00:03:40] Like you have an import and you're wondering, gosh, I think I have a declaration file for this, or I thought I downloaded an app types package for this, cuz it's kind of a black box, right? All you see is your imports not working. You thought you set everything up.

[00:03:55] This is super helpful and you can sort of, I always pipe this to a file, but you can make sense of the output of this command, and debug that way. There's also a prioritization based on file types. So, if you have a TS and a TSX file and a JS file and DTS file, all with the same file name, just differing extensions, the TS file takes precedence over TSX, which takes precedence over JavaScript and declaration file.

[00:04:26] These would be together, JS and DTS together, right, a pair. Kind of like in our dist folder, we have the index JS, index DTS. We talked a little bit about Yarn's TypeScript plugin. I don't think I need to talk about this again, except to say it downloads the app type packages for you.

[00:04:48]
>> Would you still separate declaration files for internal tools that do not have to be published?
>> That's a good question. I'm gonna interpret that two ways, answer it two ways. If it were like a CLI, I might not worry about declaration files, there's no consumer of that.

[00:05:07] But if it's an internal tool, that has some programmatic API. If you can consume it as a module, you can import it into another JS file or a TS file, I published the types. Sorry, there's one exception. Sometimes, like if it's a library that I'm in the middle of converting from JavaScript to TypeScript, I will abstain from publishing types until I'm happy with the types.

[00:05:36] So in those cases I would like to cut those out of the build before publishing, because I don't want to publish types that advertise that, like you can pass a bunch of anys into these functions. I believe that as soon as you publish a declaration file, you are stating what the public API of your library is.

[00:05:56] It's the stuff that's gonna be popping up offering type of heads autocompletes in a user's editor, and I would rather provide nothing at all than provide something that is misleading.