Quick Byte: Easy Sharing of Custom TypeScript @types Across Monorepo Packages

Olaf Tomalka
Civil
Published in
3 min readJun 29, 2018
Photo courtesy of Émile Perron

At Civil, transparency is as important for the the developers who are interested in our code as it is for the journalists who publish on our platform. As we began working with the Ethereum DApps stack, we decided to implement a monorepo in to deploy parts of our codebase independently, while standardizing linting, tests, and coverage. This has increased productivity across the entire Civil development team.

This has resulted in Civil’s developer team being able to reuse code patterns, such as internal packages and public NPM packages that are used by multiple other projects. However, we have realized that even with the monorepo structure, the TypeScript typings are extremely cumbersome, because each package requires a manual edit of each tsconfig.json file.

Many packages in the Ethereum ecosystem are written in pure JavaScript and don’t have any typings in the first place, and quite a few of those packages, such as web3, have broken typings. For us, this meant that we had to create our own typings for multiple external dependencies, such as web3, ethereumjs-abi and ethereumjs-util. This was particularly problematic because we were at a stage in which speed and iteration were of utmost importance. DefinitelyTyped and working directly with open-source projects to get pull requests would be great long-term solutions, but they were too slow and we didn’t account for those developers who had no interest in supporting TypeScript.

Our first solution was to have a .d.ts file with common definitions being copied to packages or manually sourced in every tsconfig.json file. However, this meant that we ended up with a lot of duplication and hard-to-maintain configuration files. After more than 3 packages in our monorepo that solution also stopped being viable.

Fortunately, TypeScript has an option to override the @types folder in its configuration, which works perfectly with the monorepo pattern.

Each of our packages has its own tsconfig.json, which extends the repository’s root tsconfig.json. The top-most one has all the basics as well as overridden typesRoots location. typeRoots takes an array of folders and searches them for package names on the first-come-first served basis. By setting our own typings first, we could handle broken packages with outdated or unfinished typings.

Example project structure:

.
├ tsconfig.json
│ (“typeRoots”: [“packages/typescript-typings/types”, “node_modules/@types”])
└ packages
├ typescript-typings
│ └ types
├ web3
│ ├ ethjs-util
│ └ …
├ package_1
│ └ tsconfig.json
│ (“extends”: “../../tsconfig”)
├ package_2
│ └ tsconfig.json
│ (“extends”: “../../tsconfig”)
└ …

Civil is creating an open-source project to support sustainable journalism. We’re working to make a better onramp for developers who want to start building on web3 infrastructure. Visit Civil’s GitHub to learn more, and check out the open issues if you want to contribute.

Or, if you want to reach out to me with additional feedback, email me here.

--

--