.d.ts files are called type declaration files. They exist for one purpose only: to describe the shape of an existing module and they only contain type information used for type checking.
Upon learning the basics of TypeScript, you unlock superpowers.
At least that’s how I felt.
You automagically get warnings on potential errors, you get auto-completion out of the box in your code editor.
While seemingly magical, nothing with computers are.
So, what’s the trick here, TypeScript?
In a clearer language, how does TypeScript know so much? How does it decide what API is correct or not? What methods are available on a certain object or class, and which aren’t?
The answer is less magical.
TypeScript relies on types.
Occasionally, you do not write these types, but they exist.
They exist in files called declaration files.
These are files with a
A simple example
Consider the following TypeScript code:
// valid const amount = Math.ceil(14.99) // error: Property 'ciil' does not exist on type 'Math'.(2339) const otherAmount = Math.ciil(14.99)
The first line of code is perfectly valid, but the second, not quite.
And TypeScript is quick to spot the error:
Property 'ciil' does not exist on type 'Math'.(2339)
How did TypeScript know
ciil does not exist on the
Math object isn’t a part of our implementation. It’s a standard built-in object.
So, how did TypeScript figure that out?
The answer is there are declaration files that describe these built-in objects.
Think of a declaration file as containing all type information relating to a certain module. It contains no actual implementation, just type information.
These files have a
Your implementation files will either have
These declaration files have no implementations. They only contain type information and have a
.d.ts file ending.
Built-in Type Definitions
A great way to understand this in practice is to set up a brand-new TypeScript project and explore the type definition files for top-level objects like
Let’s do this.
Create a new directory, and name it whatever’s appropriate.
I’ll call mine
Change directories to this newly created folder:
Now initialise a new project:
npm init --yes
npm install TypeScript --save-dev
This directory should contain 2 files and one subdirectory
Open the folder in your favourite code editor.
If you investigate the
TypeScript directory within
node_modules, you’ll find a bunch of type declaration files out of the box.
These are present courtesy of installing TypeScript.
By default, TypeScript will include type definition for all DOM APIs, e.g., think
As you inspect these type declaration files, you’ll notice that the naming convention is straightforward.
It follows the pattern:
Open up the
lib.dom.d.ts declaration file to view all declarations related to the browser DOM API.
As you can see, this is quite a gigantic file.
But so are all the APIs available in the DOM.
Now, if you take a look at the
lib.es5.d.ts file, you’ll see the declaration for the
Math object, containing the
Next time you think, wow, TypeScript is wonderful. Remember, a big part of that awesomeness is due to the lesser-known heroes: type declaration files.
It’s not magic. Just type declaration files.
External type definitions
What about APIs that aren’t built-in?
There’s a host of
npm packages out there to do just about anything you want.
Is there a way for TypeScript to also understand the relevant type relationships for the said module?
Well, the answer is a resounding yes.
There are typically two ways a library author may do this.
(1) Bundled Types
In this case, the author of the library has already bundled the type declaration files as part of the package distribution.
You typically don’t need to do anything.
You just go ahead and install the library in your project, you import the required module from the library and see if TypeScript should automatically resolve the types for you.
Remember, this is not magic.
The library author has bundled the type declaration file in the package distribution.
(2) DefinitelyTyped (@types)
Imagine a central public repository that hosts declaration files for thousands of libraries?
Well, bring that image home.
This repository already exists.
The DefinitelyTyped repository is a centralised repository that stores the declaration files for thousands of libraries.
In all honestly, the vast majority of commonly used libraries have declaration files available on DefinitelyTyped.
These type definition files are automatically published to
npm under the
For example, if you wanted to install the types for the
react npm package, you’d do this:
npm install --save-dev @types/react
If you find yourself using a module whose types TypeScript does not automatically resolve, attempt installing the types directly from DefinitelyTyped.
See if the types exist there. e.g.:
npm install --save-dev @types/your-library
Definition files added in this manner will be saved to
TypeScript will automatically find these. So, there’s no additional step for you to take.
Writing your declaration files
In the uncommon event that a library didn’t bundle its types and does not have a type definition file on DefinitelyTyped, you can write your own declaration files.
Writing declaration files in-depth is beyond the scope of this article, but a use case you’ll likely come across is silencing errors about a particular module without a declaration file.
Declaration files all have a
So to create yours, create a file with a
For example, assuming I have installed library
untyped-module in my project.
untyped-module has no referenced type definition files, so TypeScript complains about this in my project.
To silence this warning, I may create a new
untyped-module.d.ts file in my project with the following content:
declare module "some-untyped-module";
This will declare the module as type
We won’t get any TypeScript support for that module, but you’d have silenced the TypeScript warning.
Ideal next steps would include opening an issue in the module’s public repository to include a TypeScript declaration file, or writing out a decent one yourself.
Next time you think, wow, TypeScript is remarkable. Remember, a big part of that awesomeness is due to the lesser-known heroes: type declaration files.
Now you understand how they work!