Guards using invariant in JS

Nick - Feb 3 '22 - - Dev Community

Intro

Have you ever heard this quote? πŸ‘‡

If you want to be the best, learn from the best.

I believe that it strongly applies to programming skills πŸ’»

So in this series, we'll gradually learn top-notch JS from famous open-source projects!

πŸ‘‰ Today's topic - guards using invariant πŸ›‘οΈ

Guard is a great way to handle errors and prevent bugs in your code.
And combined with invariant it becomes an even more powerful and versatile technique πŸ’ͺ

πŸ‘‰ First of all, what is a guard?

Guard is just validation:

  • The guard checks a specific condition
  • If the condition draws to true, the guard prevents some functionality from executing
function handleInput(input) {
  const isInvalid = !input || typeof input !== 'string';

  // Here it is!
  if (isInvalid) {
    throw new Error('Input is invalid');
  }

  return getProcessedInput(input);
}
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Okay, I'll use them!

There is an issue with using guards like this.
It forces you to repeat throw new Error in dozens of places.
So, for example, if you want to add simple logging, you have to update all guards in all places.

function handleInput(input) {
  const isInvalid = !input || typeof input !== 'string';

  if (isInvalid) {
    console.log('Input is invalid'); // <- add this in all places  
    throw new Error('Input is invalid');
  }

  return getProcessedInput(input);
}
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ How to do it like a top-performer?

React developers faced the same issue and added special invariant abstraction to resolve it.

It does the same thing while preserving the DRY principle.

function handleInput(input) {
  const isValid = input && typeof input === 'string';

  invariant(isValid, 'Input is invalid');

  return getProcessedInput(input);
}
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ How does invariant work under the hood?

The most popular JS invariant implementation takes multiple arguments:

  • condition, that defines whether an error needs to be thrown
  • format, simply put, the error message
  • six optional arguments to be placed instead of %s inside the format
invariant(
  1 > 2, 
  'Hello from error. %s %s %s %s %s %s',
  1, 2, 3, 4, 5, 6
);

// Results to
// > Uncaught Error: Hello from error. 1 2 3 4 5 6
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Let's re-implement it!

As always, let's re-create invariant ourselves to get an in-depth understanding of its inner workings.

Our version uses modern ES6+ syntax and supports an indefinite number of optional arguments.

const invariant = (condition, format, ...args) => {
  if (!condition) {
    if (!format) {
      throw new Error('General error occured.');
    }

    let i = 0;

    throw new Error(format.replace(/%s/g, () => args[i++]));
  }
};
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Implement it yourself!

Go to my CodeSandbox and try to implement the invariant function, based on what we just learned.


P.S. Follow me on Twitter for more content like this!

. . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player