Comment by amake

Comment by amake 3 hours ago

4 replies

99% of my use of `satisfies` is to type-check exhaustivity in `switch` statements:

    type Foo = 'foo' | 'bar';
    
    const myFoo: Foo = 'foo';
    switch (myFoo) {
      case 'foo':
        // do stuff
        break;
      default:
        myFoo satisfies never; // Error here because 'bar' not handled
    }
mckirk an hour ago

I generally do this via a `throw UnsupportedValueError(value)`, where the exception constructor only accepts a `never`. That way I have both a compile time check as well as an error at runtime, if anything weird happens and there's an unexpected value.

inlined 3 hours ago

Nice. I didn’t know I can now replace my “assertExhaustive” function.

Previously you could define a function that accepted never and throws. It tells the compiler that you expect the code path to be exhaustive and fixes any return value expected errors. If the type is changed so that it’s no longer exhaustive it will fail to compile and (still better than satisfies) if an invalid value is passed at runtime it will throw.

  • preommr 2 hours ago

    I thought the same thing. I also have an assert function I pull in everywhere, and this trick seemed like it would be cleaner (especially for one-off scripts to reduce deps).

    But unfortunately, using a default clause creates a branching condition that then treats the entire switch block as non-exhaustive, even though it is technically exhaustive over the switch target. It still requires something like throwing an exception, which at that point you might as well do 'const x: never = myFoo'.