dwjohnston
dwjohnston

Reputation: 11803

`never` type is assignable to `number`?

I am writing some documentation about TypeScript and I'm talking about the possible usefulness of the never keyword, one being exhaustive checking, as described here:

I have some code like this:


type PossibleStrings = 'foo' | 'bar' | 'chaz'; 


function fail() : never {
    throw new Error("This endpoint should never be reached");
}

function usesString(value: PossibleStrings) : number {
    if (value === 'foo') {
        return 1
    }; 

    if (value === 'bar') {
        return 2
    }; 

    return fail();
}

Playground

Now I would expect that this would be giving an error, as you shouldn't be able to return the never type from this function.

And actually if we just strip this down, it seems like the function is a-ok with returning a never type:

type PossibleStrings = 'foo' | 'bar' | 'chaz'; 


function fail() : never {
    throw new Error("This endpoint should never be reached");
}

function usesString(value: PossibleStrings) : number {
  return fail();
}

Playground

Seems... broken. What's going on here?

Edit: Answer is right in the documentation:

The never type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, never (except never itself). Even any isn’t assignable to never.

Is there a way to change that behaviour, or otherwise get this code to behave how I want? ie. I want the return fail() to only be valid if all other branches are exhausted.

Upvotes: 1

Views: 103

Answers (1)

dwjohnston
dwjohnston

Reputation: 11803

The solution is to rather than relying on the return type of the fail function to cause compile time errors, you use the parameters of the fail function.

type PossibleStrings = 'foo' | 'bar' | 'chaz'; 


function fail(value: never) : never {
    throw new Error("This endpoint should never be reached");
}

function usesString(value: PossibleStrings) : number {
    if (value === 'foo') {
        return 1
    } 

    if (value === 'bar') {
        return 2
    }

    return fail(value); //Argument of type 'string' is not assignable to parameter of type 'never'.(2345)

}

Sandbox

When the possible values are exhaustively checked, this no longer causes a compile time error.

Upvotes: 2

Related Questions