gvergnaud/ts-pattern

Throw explicit `ExhaustiveError`

adamhamlin opened this issue · 7 comments

Is your feature request related to a problem? Please describe.

Using .exhaustive() is a critical component to type safety in an evolving codebase, but frequently "unreachable" code is, in fact, reached. Two cases that immediately come to mind:

  • You're handling some sort of unvalidated user input
  • You're working in a legacy javascript codebase which was converted to typescript and may only have "best guess" types

However, the error thrown is a vanilla Error object, and it may be difficult to distinguish from other errors and handle appropriately. For example:

try {
    const result = await match(someUserInput)
        .with('red', () => callRedApi())
        .with('white', () => callWhiteApi())
        .with('blue', () => callBlueApi())
        .exhaustive();
} catch (err) {
    if (err.message.includes('Pattern matching error')) {  // this is a weak/brittle assertion
        // bad user input -- do something
    } else {
        // good user input, but one of the callbacks error'd -- do something else
    }
}

Describe the solution you'd like
A custom error like ExhaustiveError, so the check above could use instanceof or similar. Potentially it also includes a public input variable for explicit reference of the value that did not match.

Describe alternatives you've considered

The proposal in #144 could certainly cover this. But I don't disagree that building in an explicit backdoor/fallback for .exhaustive() waters down its semantics 🤷

Additional context
N/A

Yeah, I think it would be a good idea to throw a custom error. The only thing is that last time I checked, there was difficulties with extending the native Error class when transpiling code to ES5. I don't know if this is still a problem or how many people using TS-Pattern still target ES5.

See https://stackoverflow.com/a/43595019

[EDIT] Looks like this has been fixed babel/babel#7020

Good to know re: babel. The issue does still exist with the vanilla TS compiler when targeting es5. But considering the result is that the custom error will satisfy instanceof Error--just not instanceof CustomError--it wouldn't be a breaking change, just an enhancement they can't use. That feels "good enough"? Also, yeah, still targeting es5 in 2024 seems a bit suspect.

Anyways, I can submit a PR if you're interested.

Go for it!

Just merged the PR, I'll publish this as a new minor release soon-ish. Thank you for contributing!

Just merged the PR, I'll publish this as a new minor release soon-ish. Thank you for contributing!

Sounds good, thank you