Invariant-style assertion functions in TypeScript

jser
2 min readJan 16, 2022

There is this invariant() in React source code that I found pretty useful.

It is used to assert some condition should be truthy, if not then an error should be thrown, we can simplify it to something like below.

function invariant(condition: any, message: string) {
if (!condition) {
throw new Error(message);
}
}

cases where it is useful

In a backend API which receives user input from client, we need to do data validation.

function handleInput(input: string | null) {
if (input == null) {
throw new Error("input should not be null");
}
// input is string now
const validaInput = input;
}

If we are to do it in variant style, it’ll be like this.

function handleInput(input: string | null) {
invariant(input, "input should not be null");
// input is string now
const validaInput = input;
}

But TypeScript doesn’t infer that input is not null here,validaInput is still string | null.

Assertion Function comes as rescue.

Actually it was added a long time ago in TypeScript 3.7, we can use assertion function here to tell TypeScript that if invariant doesn’t throw an error, then the input is not null.

We need invariant() to be a generic function to suit more cases.

function invariant<T>(
data: T,
message: string
): asserts data is NonNullable<T> {
if (!data) {
throw new Error(message);
}
}

Now if we try the code, validaInput has the right type of string.

Or we can assert data to be some specific type.

function assertsString(data: any): asserts data is string {
if (typeof data !== "string") {
throw new Error("data should be string");
}
}

Which is basically the same as type guard, but without the usage of if clause.

function isString(data: any): data is string {
return typeof data === "string";
}
if (isString(foo)) {
// foo is string
}

I personally like invariant-style better, how about you?

watch my Youtube video for this post: https://www.youtube.com/watch?v=BGk79_GfT7U)

--

--