Using Facebook’s invariant vs if throw
I’ve been looking at various Node.js projects’ source, and I’ve noticed that some people use invariant. From what I understood, invariant
is a tool that lets you put assertions in your code, and raise errors as needed.
Question:
When would you favor using invariant
vs throwing errors the traditional way?
// Using invariant
function doSomething(a, b) {
invariant(a > b, 'A should be greater than B');
}
// If throw
function doSomething(a, b) {
if(a <= b) {
throw new Error('A should be greater than B');
}
}
There are a few reasons:
- It’s easier to read when you want to stack them. If you have, say, 3 preconditions to validate, you always see
invariant(x ...
, and it’s easy to see what’s being checked:
function f(xs, x) {
// all the invariants are lined up, one after another
invariant(xs.type == x.type, "adding an element with the same type");
invariant(xs.length != LIST_MAX_SIZE, "the list isn't full");
invariant(fitting(x), "x is fitting right in the list");
}
Compare with the usual throw approach:
function f(xs, x) {
if (xs.type != x.type)
throw new Error("adding an element with the same type");
if (xs.length == LIST_MAX_SIZE)
throw new Error("the list isn't full");
if (!fitting(x))
throw new Error("x is fitting right in the list");
}
-
It makes it easy to eliminate it in release build.
It’s often that you want preconditions checked in dev/test, but don’t want them in release because of how slow they’d be.
If you have such aninvariant
function, you can use a tool like babel (or some other) to remove these calls from production builds
(this is somewhat like how D does it).
zertosh/invariant
allows to add code guards
As said in the readme it is A way to provide descriptive errors in development but generic errors in production.
however it is a replication of some internal facebook’s systems and imo is pretty bad documented and not maintained. Scary thing is the 4.4M uses :thinking:
- nothing will be striped out of the box
- if you don’t have a build tool that somehow remove your message in production you will still have the original error
- the usage in node is for ssr/react native, or useless outside of the “we have less lines” thing
- it uses
error.framesToPop
which also is a facebook thing
see: https://github.com/zertosh/invariant/issues?q=is%3Aissue
Note:
A better aproach will be to wait for the es proposal throw inline
and actually do
cond || throw x
cond ?? throw x
that way the error will not be evaluated anyway and stripped if cond includes a falsy var env in the browser
Usefulness in TypeScript projects
…Adding on to previous answers of making it easier to read, less lines of code, stripping from dev builds:
If you’re using typescript, you can use it help narrow down types + get dev time feedback.
Imagine the scenario below:
We’re reading from our filesystem in node/js, the type system has no idea what’s in there, so we need a runtime check, for that we’ll want an invariant method to make runtime checks like this easy.
Note:
- there is a modern & popular version Facebook’s
invariant
package calledtiny-invariant
which I recommend calledtiny-variant
: https://github.com/alexreardon/tiny-invariant