20

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');
   }
}
rodrigo-silveira
  • 10,557
  • 9
  • 55
  • 98
  • Probably just because it's one line instead of multiple lines. Same kind of pattern as `Preconditions` in Google guava (Java) – Krease Aug 20 '16 at 14:30

2 Answers2

31

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 an invariant 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).

Community
  • 1
  • 1
Ven
  • 18,663
  • 2
  • 38
  • 58
3

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

Sceat
  • 785
  • 5
  • 9