Maintaining overridden type definitions for a dependency with TypeScript

Recently, I was struggling with integrating redux-form into a TypeScript project. I hit a couple of bugs in the type definitions for this project, and I went into my node_modules and fixed them. Of course, as a good open source citizen, I submitted a couple of PRs into the DefinitelyTyped project, but in the meantime, I wanted our team be able to iterate on the project with the fixed type definitions. After a bit of Googling around, I figured it out, but it wasn't super easy to find a working, well-organized and easy-to-maintain solution. So, I decided to write a blog post acting as documentation.

  1. Create a typings/ directory somewhere in your project (it doesn't have to be named typings).
  2. Add a directory under typings/ for each dependency you want to override (e.g. typings/redux-form).
  3. Copy over the type definitions (all the .d.ts files) from node_modules or from DefinitelyTyped into the dependency's directory inside typings/.
  4. Edit your tsconfig.json and add a path mapping to each dependency like so:
{
  ...,
  "compilerOptions": {
    ...,
    "baseUrl": "src",
    "paths": {
      "redux-form": ["typings/redux-form"],
      "react-monaco-editor": ["typings/react-monaco-editor"],
      ...
    }
  }
}

Note that every directory in your paths object is relative to the baseUrl property (in our case, we have a src/typings directory).

If your change to the type definitions is incremental (i.e., you're not editing any type definitions but rather just adding new exported types), you don't have to explicitly add your overriding to compilerOption's paths. You just have to write declare module "module-name" { ... } somewhere in your code base and it extend the already-existing type definitions in node_modules.

The ability to do this is something that I missed from Flow, but I actually prefer TypeScript's more explicit approach. I hope this is useful to someone!