Link

Causewalk and error wrapping

github.com

I’m a big fan of error wrapping to provide more context.

In Go, this is standard practice:

// Hopefully something better than oh-no.
// Think contextual information that the caller has.
result, err := run()

if err != nil {
  return fmt.Errorf("Oh no: %w", err)
}Go

But in JS, we’ve had this for a while too, via Error.cause:

try {
  throw new Error()
} catch (cause) {
  throw new Error("Oh no!", { cause })
}js

Go has a couple of nice utilities for walking the error tree to see if an error matches a particular type or interface (errors.As, errors.AsType, etc.). This is great when most of the time you don’t care about the specific error, but at the edge you do. For instance, an HTTP server might care if an error is of a certain type when choosing the right response status code.

There are a bunch of error libraries out there, but I’ve just published a super tiny one that scratches my personal itch for these helpers: causewalk.

Here’s an example:

import { is } from "causewalk"
import { CardDeclinedError } from "./payments"

try {
  await checkout(order)

  return response.status(204).send()
} catch (error) {
  // Does any error in the chain match `CardDeclinedError`?
  if (is(error, CardDeclinedError)) {
    return response.status(402).send({ message: "Card was declined" })
  }

  return response.status(500)
}TypeScript

I really do mean small: the surface area today is just three simple functions that share the same helper for walking errors. Copy-paste it, install it or use it as a starting point. I love things like neverthrow, but often they require too much investment and buy-in.