Blog

News from the bpmn.io project

Type Declarations for bpmn-js

Published by Nico Rehwaldt on Tuesday, 09 January 2024.

bpmn-js13.0.0 diagram-js12.0.0

Earlier last year, bpmn-js@13 shipped with a single feature: Built-in type declarations. Learn how they help you get the most out of your editor tooling as you work with bpmn-js, whether through code completion, introspection, or validation. Look behind the scenes and understand how we ended up creating these declarations.

Advanced code intelligence for JavaScript (and TypeScript) in modern code editors relies on a single feature: Type declarations. Type declarations, shipped with the libraries you use, superpower your code editor, allow for auto-completion, and enable static syntax checking.

With bpmn-js@13, we made this utility available for users, too:

Code completion for bpmn-js in a modern editor.

Code completion for bpmn-js in a modern editor.

Using the Declarations

Type declarations ship out of the box, starting with bpmn-js@13. A modern code editor picks those up automatically or with minimal configuration effort.

We implemented types so that event listeners (Diagram#on) and service getters (Diagram#get) are generics. Cast them to the appropriate type as you use the library:

import BpmnViewer from 'bpmn-js/lib/Viewer';

/**
 * @typedef {
 *   import('diagram-js/lib/core/ElementRegistry').default
 * } ElementRegistry
 */

const viewer = new BpmnViewer();

/**
 * @type { ElementRegistry }
 */
const elementRegistry = viewer.get('elementRegistry');

const element = elementRegistry.get('MY_TASK');

console.log(element.id); // MY_TASK

Check out the full types example to learn more about bpmn-js type declarations and their use cases.

Under the Hood

Our code base has already had comprehensive JSDoc hints for years. Those annotations captured loads of crucial information on how things work. They were never accessible to library consumers, though.

In early 2023, we started to explore ways to make type information and linked documentation available to users of bpmn.io. The obvious way was to provide type declarations with our libraries. But typing a vast, multi-layered code base with more than 160,000 lines of code posed a unique challenge.

We ended up generating the type declarations. Before, though, we polished our existing JSDoc declarations and added type specs and interface types (where missing). To generate the actual declarations, we use bio-dts. It is a utility that produces clean type definitions from idiomatic JavaScript, all while keeping documentation and additional meta-data intact.

Today, every service is accompanied by its type declaration (generated and shipped to library consumers) as well as a test that verifies the declarations satisfy expected usage patterns:

lib
├── core
│   ├── EventBus.js        (original, shipped)
│   ├── EventBus.d.ts      (generated, shipped)
│   ├── EventBus.spec.ts   (not shipped)
│   └── ...
└── ...

Wrapping up

This blog introduced the type declarations that first shipped out-of-the-box with bpmn-js@13. We hope those declarations make you more productive as you work with bpmn-js. We look forward to using our generator toolchain to bring type declarations to more bpmn.io libraries.

Did we miss anything? Did you spot a bug, or would you like to suggest an improvement?

Contact us via our forums, follow us on Mastodon, and file any issue you find in the respective toolkit issue trackers.

Are you passionate about JavaScript, modeling, and the web?
Join Camunda and build modeling tools people heart.