outvariant

Type-safe implementation of invariant with positionals.

Usage no npm install needed!

<script type="module">
  import outvariant from 'https://cdn.skypack.dev/outvariant';
</script>

README

outvariant

Type-safe implementation of invariant with positionals.

Motivation

Type-safely

This implementation asserts the given predicate expression so it's treated as non-nullable after the invariant call:

// Regular invariant:
invariant(user, 'Failed to fetch')
user?.firstName // "user" is possibly undefined

// Outvariant:
invariant(user, 'Failed to fetch')
user.firstName // OK, "invariant" ensured the "user" exists

Positionals support

This implementation uses rest parameters to support dynamic number of positionals:

invariant(predicate, 'Expected %s but got %s', 'one', false)

What is this for?

Invariant is a shorthand function that asserts a given predicate and throws an error if that predicate is false.

Compare these two pieces of code identical in behavior:

if (!token) {
  throw new Error(`Expected a token to be set but got ${typeof token}`)
}
import { invariant } from 'outvariant'

invariant(token, 'Expected a token to be set but got %s', typeof token)

Using invariant reduces the visual nesting of the code and leads to cleaner error messages thanks to formatted positionals (i.e. the %s (string) positional above).

Usage

Install

npm install outvariant
# or
yarn add outvariant

You may want to install this library as a dev dependency (-D) based on your usage.

Write an assertion

import { invariant } from 'outvariant'

invariant(user, 'Failed to load: expected user, but got %o', user)

Positionals

The following positional tokens are supported:

Token Expected value type
%s String
%d/%i Number
%j JSON (non-stringified)
%o Arbitrary object or object-like (i.e. a class instance)

Whenever present in the error message, a positional token will look up the value to insert in its place from the arguments given to invariant.

invariant(
  false,
  'Expected the "%s" property but got %j',
  // Note that positionals are sensitive to order:
  // - "firstName" replaces "%s" because it's first.
  // - {"id":1} replaces "%j" because it's second.
  'firstName',
  {
    id: 1,
  }
)

Contributing

Please open an issue or submit a pull request if you wish to contribute. Thank you.