Writing Declaration Files for @types
.d.ts files), you can avoid misusing libraries and get things like completions in your editor.
As a recap of that previous blog post, if you’re using an npm package named
foo-bar and it doesn’t ship any
.d.ts files, you can just run
npm install -S @types/foo-bar
and things will just work from there.
But you might have asked yourself things like “where do these ‘at-types’ packages come from?” or “how do I update the
.d.ts files I get from it?”. We’re going to try to answer those very questions.
The simple answer to where our
@types packages come from is DefinitelyTyped. DefinitelyTyped is just a simple repository on GitHub that hosts TypeScript declaration files for all your favorite packages. The project is community-driven, but supported by the TypeScript team as well. That means that anyone can help out or contribute new declarations at any time.
Authoring New Declarations
Let’s say that we want to create declaration files for our favorite library. First, we’ll need to fork DefinitelyTyped, clone your fork, and create a new branch.
git clone https://github.com/YOUR_USERNAME_HERE/DefinitelyTyped cd DefinitelyTyped git checkout -b my-favorite-library
Next, we can run an
npm install and create a new package using the
new-package npm script.
npm install npm run new-package my-favorite-library
For whatever library you use,
my-favorite-library should be replaced with the verbatim name that it was published with on npm.
If for some reason the package doesn’t exist in npm, mention this in the pull request you send later on.
new-package script should create a new folder named
my-favorite-library with the following files:
Finally we can get started writing our declaration files. First fix up the comments for
index.d.ts by adding the library’s MAJOR.MINOR version, the project URL, and your username. Then, start describing your library. Here’s what
my-favorite-library/index.d.ts might look like:
// Type definitions for my-favorite-library x.x // Project: https://github.com/my-favorite-library-author/my-favorite-library // Definitions by: Your Name Here <https://github.com/YOUR_GITHUB_NAME_HERE> // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped export function getPerpetualEnergy(): any; export function endWorldHunger(n: boolean): void;
Notice we wrote this as a module – a file that contains explicit imports and exports. We’re intending to import this library through a module loader of some sort, using Node’s
require() function, AMD’s
define function, etc.
Now, this library might have been written using the UMD pattern, meaning that it could either be imported or used as a global. This is rare in libraries for Node, but common in front-end code where you might use your library by including a
<script> tag. So in this example, if
my-favorite-library is accessible as the global
MyFavoriteLibrary, we can tell TypeScript that with this one-liner:
export as namespace MyFavoriteLibrary;
So the body of our declaration file should end up looking like this:
// Our exports: export function getPerpetualEnergy(): any; export function endWorldHunger(n: boolean): void; // Make this available as a global for non-module code. export as namespace MyFavoriteLibrary;
Finally, we can add tests for this package in
import * as lib from "my-favorite-library"; const energy = lib.getPerpetualEnergy(); lib.endWorldHunger(true);
And that’s it. We can then commit, push our changes to GitHub…
git add ./my-favorite-library git commit -m "Added declarations for 'my-favorite-library'." git push -u origin my-favorite-library
…and send a pull request to the
master branch on DefinitelyTyped.
Once our change is pulled in by a maintainer, it should be automatically published to npm and available. The published version number will depend on the major/minor version numbers you specified in the header comments of
Sometimes we might find ourselves wanting to update a declaration file as well. For instance, let’s say we want to fix up
getPerpetualEnergy to return an array of
In that case, the process is pretty similar. We can simply fork & clone DefinitelyTyped as described above, check out the
master branch, and create a branch from there.
git clone https://github.com/YOUR_USERNAME_HERE/DefinitelyTyped git checkout -b fix-fav-library-return-type
Then we can fix up our library’s declaration.
- export function getPerpetualEnergy(): any; + export function getPerpetualEnergy(): boolean;
And fix up
my-favorite-library‘s test file to make sure our change can be verified:
import * as lib from "my-favorite-library"; // Notice we added a type annotation to 'energy' so TypeScript could check it for us. const energy: boolean = lib.getPerpetualEnergy(); lib.endWorldHunger(true);
Many packages in the
@types repo will end up depending on other type declaration packages. For instance, the declarations for
react-dom will import
react. By default, writing a declaration file that imports any library in DefinitelyTyped will automatically create a dependency for the latest version of that library.
If you want to snap to some version, you can make an explicit
package.json for the package you’re working in, and fill in the list of dependencies explicitly. For instance, the declarations for leaflet-draw depend on the the
@types/leaflet package. Similarly, the Twix declarations package has a dependency on
moment itself (since Moment 2.14.0 now ships with declaration files).
As a note, only the
package.json is necessary, as the DefinitelyTyped infrastructure will provide the rest.
Quicker Scaffolding with dts-gen
We realize that for some packages writing out every function in the API an be a pain. Thats why we wrote dts-gen, a neat tool that can quickly scaffold out declaration files fairly quickly. For APIs that are fairly straightforward, dts-gen can get the job done.
For instance, if we wanted to create declaration files for the array-uniq package, we could use dts-gen intsead of DefinitelyTyped’s
new-package script. We can try this our by installing dts-gen:
npm install -g dts-gen
and then creating the package in our DefinitelyTyped clone:
cd ./DefinitelyTyped npm install array-uniq dts-gen -d -m array-uniq
-d flag will create a folder structure like DefinitelyTyped’s
new-package script. You can peek in and see that dts-gen figured out the basic structure on its own:
export = array_uniq; declare function array_uniq(arr: any): any;
You can even try this out with something like TypeScript itself!
Keep in mind dts-gen doesn’t figure out everything – for example, it typically substitutes parameter and return values as
any, and can’t figure out which parameters are optional. It’s up to you to make a quality declaration file, but we’re hoping dts-gen can help bootstrap that process a little better.
dts-gen is still in early experimental stages, but is on GitHub and we’re looking feedback and contributions!
A Note About Typings, tsd, and DefinitelyTyped Branches
If you’re not using tools like tsd or Typings, you can probably skip this section. If you’ve sent pull requests to DefinitelyTyped recently, you might have heard about a branch on DefinitelyTyped called
types-2.0 branch existed so that infrastructure for
@types packages wouldn’t interfere with other tools.
However, this was a source of confusion for new contributors and so we’ve merged
master. The short story is that all new packages should be sent to the
master branch, which now must be structured for for TypeScript 2.0+ libraries.
Tools like tsd and Typings will continue to install existing packages that are locked on specific revisions.
Our team wants to make it easier for our community to use TypeScript and help out on DefinitelyTyped. Currently we have our guide on Publishing, but going forward we’d like to cover more of this information on our website proper.
We’d also like to hear about resources you’d like to see improved, and information that isn’t obvious to you, so feel free to leave your feedback below.
Hope to see you on DefinitelyTyped. Happy hacking!