Typescript declaration files of external libraries: an introduction to Typings

Typescript is hot! It seems like Microsoft has finally managed to get the Dev community to love them again instead of the usual hate.

So, you want to start your first Typescript project, you get follow the “Quick Start” from the typescriptlang documentation. This is easy 😎. You feel ready to start on this node pokemon go library you’ve been wanting to write for ages now, all in Typescript!

Then you notice, your amazing library should actually depend on a different library, node-fetch. Easy right, just npm install it? Well not really. The creators of node-fetch used plain javascript in his package (not even ES6, what a savages). So now your stuck with an external package of which you don’t have any typings. And your typescript compiler will complain:

error TS2307: Cannot find module 'node-fetch'.

The easiest solution would be to just drop a placeholder for your module in a declaration file:

// index.d.ts
declare module 'node-fetch' {
var main: any
export = main
}

Although this does work, it’s quite unfortunate you won’t be able to check any the types coming from methods and variable you imported. You could of course just write the declaration file of the API you imported yourself, but you have this library to write. Nobody got time for that!

Typings and importing declaration files

Luckily, other devs are facing the same issue as you are right now, and some of them were a bit less selfish than you and actually wrote the declaration file!

Originally, they organized in one repo: DefinitelyTyped. This is probably still the main source of declaration files. However, there is one big flaw with DefinitelyTyped: all the declarations are “global” and as a result, it is impossible to handle dependencies well.

For example, take redux-thunk, a middleware for redux, and therefore incredibly intertwined with redux and redux types. The declaration file of redux-thunk could look something like this:
import { Middleware } from "redux";

// redux-thunk/index.d.ts
import { Middleware } from "redux";
declare const thunk: Middleware & {
withExtraArgument(extraArgument: any): Middleware;
};
export default thunk;

DefinitelyTyped will resolve this dependency by adding a relative reference to the proper declaration file as in DefinitelyTyped. However, what if there is no declaration yet in of this package, it is outdated or you just want to use another declaration file? For redux for example, there is a declaration file being maintained inside the redux repo itself. Why can’t we just use that one as the dependency?

Enters the stage: typings. Typings provides a cli and framework to (quite) easily search through all different kinds of potential sources of declaration files. Moreover, as a bonus, it supports functionality for different declaration files for different versions of the same package.

Right now, the Typings search api looks through two main sources: DefinitelyTyped definitions and an own registry where they store typings references to vetted declaration files.

However, you can also use Typings to install directly from a index.d.ts file or from a typings.json file. If you install directly for the declaration file, it is recommended to supply a name, as typings won’t know otherwise the name of the module you’re installing. Eg:

$ typings install --save --name redux github:reactjs/redux/index.d.ts#50b97f855ecf95417a73bab4c7771b15bf624828

Well, you’re all set now. Unless, of course, nobody has taken the time yet to publish a declaration file. Well, then it’s up to you to create one no? But that’ll be for another post!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.