Typescript definitions. What a confusing topic. Prior to Typescript 2.0 we were using tools like
typings to manage and install them. After 2.0 we moved to
@types, but what does that really mean? And how can we migrate an existing project that uses
typings? What about custom type definitions?
In this post I will show you how to migrate to newest
@types, answering all these questions.
Let’s work with a project that has typings from the typings repository and also custom ones. We need to preserve the project’s structure in code, the only thing we need is to get rid of
typings.json and its definition files that are installed with it.
Before we do that though, let’s dig into some useful information on typings.
Typescript Definition Manager
These issues, you will agree, are hard to discover when you are developing and can lead to unstable code.
But what about third party libraries, like jQuery or Angular? These, you don’t have any authority over and Typescript cannot understand the libraries specific objects, like
angular. Compiler won’t be able to understand those objects and will throw an error if you reference them.
So, in order to use such libraries with Typescript, you need to get files that describe their public API. These are type definition files, with a file extension of
The Typescript Definition Manager is a solution to that problem, as it provides a single way to manage and install Typescript definitions, by using a typings.json file to resolve the library specific types from various repositories, like the typings registry, Github, NPM or even custom online or local files.
Okay, and what is that
@types comes to solve the problem of using another third party tool for this job. Many people have plead for making Typescript support resolving these definition types internally.
This is a feature that was introduced in Typescript 2.0. All the type definition files that were part of the
typings project are moved to NPM now, so one can download the directly from there with a simple command
As you can see, installation is fairly simple. Of course, the compiler was modified accordingly to resolve these types automatically, supporting global and module type definitions.
Global definitions are by default any definitions that support global consumption and they are included automatically.
For module definitions, no special configuration is required after the installation, you just use it like a module
There are ~3274 @types packages available at npm at the moment. Take a look here.
Now that we got some background on them, let’s move to the actual project.
First of all, make sure you have installed Typescript version >= 2.0. I have 2.3.3 version installed.
I installed Typescript globally on my machine and also locally on my project, so my code can be compiled on the CI.
Next, remove type definitions from
My typings file contains the following global dependencies
As you can see, it contains definitions directly from the registry and also some custom ones (the
file:typings/custom/*). We want to remove all these from the
Also, note that my custom definitions are under the
typings/custom/ directory. I want to keep that directory, so I can register the custom type definitions with the
I use VS Code here, but you can do it with your command prompt from the location of the
typings.json file. So, on VS Code, open the terminal (
Ctrl + `) and start removing definitions using the following commands:
rm command is just an alias to the
uninstall command. The
-SG flag is removing from globals directory. So, for example, I want to remove the angular typed definition
I removed all the rest using the same command.
After you have removed all the definitions, go ahead and remove the
typings.json file. Also, uninstall the
typings from the npm modules.
My working directory looks like the following now:
Awesome! Next step is to configure
tsconfig.json to register these definitions as globals and to install all
@types for the rest of the libraries.
Let’s first install all the @types modules and then configure the
I will not explain all those properties, rather than stand on
typerRoots and a bit on
As you know, exclude is used to exclude files from compilation process, so I excluded all typescript under
typings directories. Remember, I have custom types under the typings folder.
typeRoots. As you know, @types are automatically included in the compilation. If you are casually saving your @types under
node_modules/@types, then they will be automatically picked up by the compiler and will be globally available (just like having them as globals in typings). But what happens when you want to have other types, like custom ones available also? And they are in an entirely different folder from
node_modules/@types? You need to explicitly tell the compiler to look not only on
node_modules/@types but to other directories as well.
typeRoots compiler option. This option allows loading typing declarations from folders which have an NPM format, meaning they contain an
index.d.ts file. The default for the
Now you understand why
node_modules/@types is by default picked up.
Typescript goes to that folder and tries to load every sub-folder that is an npm package. Essentially, the
typeRoots property is useful for loading global declarations.
The thing is that it loads as global every declaration under the folder structure(s) that it is instructed to look. If you wish to be explicit on what you want to be loaded as globals, then you should use the
Looking on the
tsconfig.json you can understand that declarations are loaded from
node_modules/@types and from
One more thing I need to do is to fix some of my Typescript definition files, as they use the
/// <reference path="..." /> to reference other definitions inside those
.d.ts files. These references need to be removed, so, I visited each of the
typings/custom/*/index.d.ts files to do so.
Let’s try to compile now…
No problem at all! I successfully migrated my Typescript definitions!
In this post I presented some key points on typings definition manager and @types. I quickly and detailed demonstrated a seamless migration from old definitions to new ones, preserving the custom definitions in the same time. I discussed on how the compiler is tied to resolving global or module type definitions.
Hope you enjoyed that, see you next time!
If you liked this blog post, please like, share and subscribe! For more, follow me on Twitter @giorgosdyrra.