Assertions in JavaScript
Assertions are a great way of catching errors during development. Since they’re inlined with your code they’re much cheaper to write than unit tests, while doing a better job of acting as documentation. I like to think of them as comments that actually enfore what they’re saying.
const value = values[i]!;
assert(value !== undefined, `values[${i}] must be defined`)
Many languages have first party assertions, but JS doesn’t. The closest thing is the node:assert
module, which isn’t available in browsers.
There are some additional complexities surrounding assertions with the JS ecosystem specifically.
- Code is often bundle-size constrained. Adding assertions everywhere would bloat bundles.
- JS projects often use a lot of libraries. Consumers of libraries should get the final say about what happens if an assertion in a library fails (fatal/log/ignore).
Ideally we would want assertions that:
- Run in every JS environment
- Can automatically be stripped from client side bundles to avoid bloat
- Are non-fatal by default & can be made fatal by the final consumer
I’ve found that console.assert
meets these criteria really well. It is universally supported, non-fatal by default, and easy for build tools to remove. Here is what I’ve been doing:
- Add
console.assert
calls liberally througout my code - If I’m writing a library I do not strip out assertions before publishing
- If I’m writing an app I use EsBuild’s
drop
option to removeconsole.assert
calls from client builds. In vite this can be done via theesbuild
option. I don’t remove assertions from the server-side build. - I monkey-patch
console.assert
to be fatal in server-side code.
So far this has been working well for me