0

Below is the example code from my textbook:

function calculateTax(amount: number, format: boolean): string | number {
    const calcAmount = amount * 1.2;
    return format ? `$${calcAmount.toFixed(2)}` : calcAmount;
}

let taxValue = calculateTax(100, false);

switch (typeof taxValue) {
    case "number":
        console.log(`Number Value: ${taxValue.toFixed(2)}`);
        break;
    case "string":
        console.log(`String Value: ${taxValue.charAt(0)}`);
        break;
    default:
        let value: never = taxValue;   // taxValue's type is "never"
        console.log(`Unexpected type for value: ${value}`);
}

and the author says:

TypeScript provides the never type to ensure you can’t accidentally use a value once type guards have been used to exhaustively narrow a value to all of its possible types

I'm confused, in the the default branch, I can assign the never type to any other types as:

default:
   let value: number = taxValue; // or let value: number = taxValue;        
   console.log(`Unexpected type for value: ${value}`);

so what does the author mean by "can’t accidentally use a value"? and what's the purpose of never in this example, I can't see any benefits to use "never" type.

  • 1
    `never` means that it never shows up. It's for occasions where syntax allows you to get a variable but you shouldn't in practice, for example `function alwaysThrows() { throw "some error"};` is never going to return anything, yet it's syntactically valid to have `var myVar = alwaysThrows()`. In TS `myVar` would have the `never` type, sine it will never really be assigned. `never` can also occur if type guards exclude all other valid types. – VLAZ Sep 19 '19 at 06:18
  • 2
    As for the example - I probably need to see it in context to understand it better but it *seems* like the author means that `taxValue` would be of the `never` type, since it's neither a number nor a string - it goes through two type guards and disqualifies both members of the `string | number` union, so you are left with nothing. Manually declaring `let value: never` doesn't make much sense - it's a declaration of a variable that shouldn't exist and shouldn't be used. – VLAZ Sep 19 '19 at 06:20

1 Answers1

2

Although never tends to be seen as a sort of error type it is not. never is the subtype of every type, as stated in the PR introducing it:

never is a subtype of and assignable to every type.

This means that you can assign never to any other type, it is a universal source. What you can't do is assign anything to never:

declare let a:never
let b: string = a;
a = b // error
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
  • so could you provide an example to show the benefits of using never type, I can't see any reasons to use that –  Sep 19 '19 at 13:50
  • @secondimage `never` is there to represent a type that, according to the type system, can't occur at runtime, it's just that the type itself is not an automatic error. Even in your example the assignment `let value: never = taxValue;` will fail if `taxValue` has not been narrowed to `never` (ie forgotten case). However you still want to be able to log the invalid value with the subsequent `console.log`, ts needs to let you do this. So you can assign `never` as the parameter to a logging function, or concatenate it in your string, even though the type system does not think it can really happen. – Titian Cernicova-Dragomir Sep 19 '19 at 14:20