Typings for Architect Functions

avatar
Taylor Beseda
June 30, 2022

The latest release of @architect/functions, Arc’s Node.js runtime helpers, has bundled type definitions.

Node.js modules can provide type definitions via the types key in their package.json. These typings offer several benefits to both TypeScript and JavaScript developers. Explicit, hand-crafted types enable editor IntelliSense, inline error checking, and powerful autocomplete for dynamic properties like @architect/functions’ tables client:

types in action

Our Approach

The Arc team most definitely did not want to rewrite @architect/functions in TS; in fact, we didn’t want to alter any library code. It turns out, this is easy.

Custom-built

We used a common pattern where type definition files (*.d.ts) are kept in a types directory at the project root. Each file declares types and interfaces for individual public1 APIs and is then rolled up and exported from ./types/index.d.ts. This index file is then referenced in the library’s package.json so that definitions are automatically available to users’ tooling. Huge “Thank you!” to Cam Jackson for authoring these types by hand.

Tested

Cam also set up tests for the more complex APIs with dtslint – a type definition testing utility provided by the TypeScript team at Microsoft. The tests exercise the library as a user might and include inline error assertions. dtslint uses TypeScript to check the validity and expectations, failing as needed. We did find dtslint to be a bit slow to run in our main testing loop: a couple thousand assertions run in under a second on my machine, whereas dtslint can take 15+ seconds to complete. Instead, we moved it to a separate workflow in our GitHub actions.

Maintenance cost

Bundling types in a package that is not authored with TypeScript does incur some overhead for maintainers. Type definitions do not automatically update when the library does. Fortunately, the userland API for @architect/functions is fairly hardened and hasn’t shifted much in several years. Our type definitions will only need to be updated if and when the external API changes; something we try to avoid as much as possible.

Moving away from DefinitelyTyped

DefinitelyTyped is a great alternative to bundling types. However, community-provided types can lag as new releases are cut. Editors can be configured to automatically discover known types from DefinitelyTyped, but users often have to intentionally search for and install @types/* typings. Mature projects should include their own definitions to be able to author and test typings alongside actual library code. Even purely JavaScript modules can benefit from including types in the project repository.

Avoid drift. Bundle your types.

1 The typings do not cover internal interfaces, those are provided inline with JSDoc comments.