Skip to content

invariant-style type guard #19066

@sgoll

Description

@sgoll

TypeScript Version: 2.5.3

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

function double(a: number | string) {
    invariant(typeof a === 'number', 'Sorry, strings not supported yet');
    return a * 2;
}

(Playground)

Expected behavior:

invariant should establish a type guard for the code following the invariant statement.

Actual behavior:

TypeScript errors with error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.

This is because a still resolves to type string | number.

Suggestion:

invariant ensures that its first argument condition is truthy, and throws otherwise, i.e. when the code following the invariant statement is reached it is safe to make all the same assumptions as if that code were wrapped in if (condition) { … }, or equivalently, the invariant were replaced with its literal implementation.

Although the latter works as a regular type guard (if (typeof a !== 'number') { throw … }), it makes the code unnecessarily verbose. I think there should be a way of declaring that a given function guarantees that some guard is active, and never returns otherwise, i.e. something like this (pseudo code):

declare function invariant(condition: any, message: string): void if testValue;

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions