tiny-invariant is a tiny, widely-supported, zero-dependency alternative to invariant.
tiny-invariant - when every byte counts!
An invariant function takes a value, and if the value is falsy then the invariant function will throw. If the value is truthy, then the function will not throw.
import invariant from 'tiny-invariant';
invariant(truthyValue, 'This should not throw!');
invariant(falsyValue, 'This will throw!');
// Error('Invariant violation: This will throw!');The library: invariant supports passing in arguments to the invariant function in a sprintf style (condition, format, a, b, c, d, e, f). It has internal logic to execute the sprintf substitutions. The sprintf logic is not removed in production builds. tiny-invariant has dropped all of the code for sprintf logic and instead encourages consumers to leverage template literals for message formatting.
invariant(condition, `Hello, ${name} - how are you today?`);tiny-invariant allows you to pass a string message, or a function that returns a string message. Using a function that returns a message is helpful when your message is expensive to create.
import invariant from 'tiny-invariant';
invariant(condition, `Hello, ${name} - how are you today?`);
// Using a function is helpful when your message is expensive
invariant(value, () => getExpensiveMessage());When process.env.NODE_ENV is set to production, the message will be replaced with the generic message Invariant failed.
tiny-invariant is useful for correctly narrowing types for flow and typescript
const value: Person | null = { name: 'Alex' }; // type of value == 'Person | null'
invariant(value, 'Expected value to be a person');
// type of value has been narrowed to 'Person'conditionis required and can be anythingmessageoptionalstringor a function that returns astring(() => string)
# yarn
yarn add tiny-invariant
# npm
npm install tiny-invariant --saveBig idea: you will want your compiler to convert this code:
invariant(condition, 'My cool message that takes up a lot of kbs');Into this:
if (!condition) {
if ('production' !== process.env.NODE_ENV) {
invariant(false, 'My cool message that takes up a lot of kbs');
} else {
invariant(false);
}
}- Babel: recommend
babel-plugin-dev-expression - TypeScript: recommend
tsdx(or you can runbabel-plugin-dev-expressionafter TypeScript compiling)
Your bundler can then drop the code in the "production" !== process.env.NODE_ENV block for your production builds to end up with this:
if (!condition) {
invariant(false);
}- rollup: use rollup-plugin-replace and set
NODE_ENVtoproductionand thenrollupwill treeshake out the unused code - Webpack: instructions
- We have a
es(EcmaScript module) build - We have a
cjs(CommonJS) build - We have a
umd(Universal module definition) build in case you needed it
We expect process.env.NODE_ENV to be available at module compilation. We cache this value
🤘