Invariant what is it?
Looking at what invariant means in the context of Computer Science and why it is useful.
Invariant comes from mathematics which defines it as a property that is guaranteed not to change. The common example being the rotation of a triangle: you can say that the triangle’s side lengths are invariant.
In computer science, invariant means the same but in a specific context. It is a condition of a program that during some period of execution is guaranteed not to change.
So why is invariant useful and how does it relate to TypeScript. There are a few libraries that essentially do the same thing:
They do nothing if a truthy value is passed or throw an error if a falsy value is passed. I think of it like an assert function, because invariant is not in my general vocabulary.
TypeScript comes into play by providing type narrowing. For example:
import function invariant(condition: any, message?: string | (() => string)): asserts conditioninvariant from "tiny-invariant";
function function fn(argument: string | null): voidfn(argument: string | nullargument: string | null) {
function invariant(condition: any, message?: string | (() => string) | undefined): asserts conditioninvariant(argument: string | nullargument);
var console: Consoleconsole.Console.log(...data: any[]): voidlog(argument: stringargument);
}
As you can see argument is of type string instead of string | null, because TypeScript knows invariant will throw if argument is falsy, it can rule out null.
A great use case for this is checking for required parameters in a context where you cannot guarantee their values, like user input. Remix make use of tiny-invariant Remix make use of tiny-invariant in their examples for this very purpose (which is where I first learned about the concept).
To see how invariant actually works we can implement it ourselves:
function function invariant(value: any): asserts valueinvariant(value: anyvalue: any): asserts value: anyvalue {
if (value: anyvalue) {
return;
}
throw new var Error: ErrorConstructor
new (message?: string | undefined, options?: ErrorOptions | undefined) => Error (+1 overload)Error(`${value: anyvalue} is falsy`);
}
function function fn(argument: string | null): voidfn(argument: string | nullargument: string | null) {
function invariant(value: any): asserts valueinvariant(argument: string | nullargument);
var console: Consoleconsole.Console.log(...data: any[]): voidlog(argument: stringargument);
}
This uses a new keyword added to TypeScript 3.7 asserts which determines that argument must be true if it returns. Otherwise, the function will throw an error which is what we want here!