Execute Program

Everyday TypeScript: Never

Welcome to the Never lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • Some functions never return. For example, a function that always throws an exception never returns.

  • >
    function throws() {
    throw new Error('oh no');
    }
    throws();
    Result:
  • What should this function's return type be? TypeScript will infer it to have a return type of void. But that doesn't fully capture what's happening.

  • The void type is for functions that begin, do some work, and finish, but don't return a value. Our function above is different: if we call it, then the code after that call will never execute at all.

  • Fortunately, there's a TypeScript type for that: never.

  • >
    function throws(): never {
    throw new Error('oh no');
    }
    throws();
    Result:
  • The never type is a bit strange. It's assignable to any other type. The next example is like the example above, except that it assigns the never return value to a number variable. The function still throws an exception, so the answer here is the same as above.

  • (When code will result in an error thrown at runtime, you can answer with error.)

  • >
    function throws(): never {
    throw new Error('oh no');
    }
    const n: number = throws();
    Result:
    Error: oh noPass Icon
  • At first, it seems like never is acting like any, because we're allowed to assign the never to a number (or a string, or anything else). But unlike any, this is safe!

  • The compiler knows that our throws function never returns, so it also knows that nothing will ever be assigned to the n variable. Types exist to ensure that the data is correct at runtime. If the compiler knows that the assignment will never happen at runtime, then the variable's type doesn't matter.

  • However, we can't assign any other type to never. That would break the rule of never: it never actually holds a value at runtime. Trying to assign any value to a never is always a type error.

  • (When a code example contains a type error, you can answer with type error.)

  • >
    const aNever: never = 5;
    aNever;
    Result:
    type error: Type '5' is not assignable to type 'never'.Pass Icon
  • Absolutely nothing can be assigned to a never; not even an any!

  • >
    const anAny: any = 5;
    const aNever: never = anAny;
    aNever;
    Result:
    type error: Type 'any' is not assignable to type 'never'.Pass Icon
  • If a function always throws, but has no explicit return type, then TypeScript will infer a void return type. That's not bad, but it's better to explicitly mark it as never, which gives TypeScript a bit more information to work with.

  • For example, suppose that a function calls another function, returning its return value. If the inner function returns never, TypeScript will correctly infer that the outer function's return type is also never.

  • >
    function throws(): never {
    throw new Error('oh no');
    }

    function alsoThrows() {
    return throws();
    }

    const n: number = alsoThrows();
    Result:
  • That code compiled, which tells us that alsoThrows has a return type of never. (If it returned void, then the const n: number = alsoThrows() line would type error, because we can't assign a void to a number.)

  • However, this type inference doesn't rely on any special TypeScript behavior around never. It's just normal TypeScript type inference: alsoThrows returns throws(), so it has the same return type as throws.

  • Here's a code problem:

    First, run this code to see that it doesn't error. Then change its return type to never. That will cause a type error, because the function does return. TypeScript won't allow a never function to return a value.

    function f(): never {
    return 5;
    }
    Goal:
    type error: Type '5' is not assignable to type 'never'.
    Yours:
    type error: Type '5' is not assignable to type 'never'.Pass Icon
  • TypeScript also won't let a never function return conditionally (for example, inside an if). If there's any way for a function to return a value, then its return type can't be never; that wouldn't make sense.

  • (The next example has a type error for exactly that reason.)

  • >
    function forcePositive(x: number): never {
    if (x > 0) {
    return x;
    } else {
    throw new Error('Number was negative!');
    }
    }
    Result:
    type error: Type 'number' is not assignable to type 'never'.Pass Icon
  • The never type applies to more than just exception-throwing functions. For example, a function with an infinite loop can (and should!) have a return type of never.

  • Unfortunately, we can't show a live example of that here because it would never terminate. However, we can show the opposite: a function that looks kind of like an infinite loop, and claims to be a never, but will sometimes return. That's a type error.

  • >
    function f(): never {
    while (true) {
    if (Math.random() < 0.000001) {
    break;
    }
    }
    }
    Result:
    type error: A function returning 'never' cannot have a reachable end point.Pass Icon
  • Finally, a quick summary of void and never.

  • void means that the function eventually terminates, but it doesn't return any value. The function either has no return statement, or it has a bare return; statement with no value after it. The void type isn't assignable to anything because it represents the absence of a value.

  • never means that the function never terminates normally. It might throw an exception or go into an infinite loop. If we're in a server-side system like Node, it might call process.exit() to terminate the process. One way or another, execution never reaches the end of the function. The never type is assignable to anything because the compiler knows that the assignment will never actually happen at runtime.