gvergnaud / ts-pattern

🎨 The exhaustive Pattern Matching library for TypeScript, with smart type inference.
MIT License
12.5k stars 135 forks source link

`exhaustive` doesn't work when the conditions use an enum with numeric values #183

Open alcuadrado opened 1 year ago

alcuadrado commented 1 year ago

Describe the bug

If you try to match over a type who's discriminating field is an enum with numeric values, exhaustive() seems to get lost and produces a type error when it's not needed.

Code Sandbox with a minimal reproduction case https://www.typescriptlang.org/play?target=9&jsx=0&module=7#code/JYWwDg9gTgLgBAbziAhjAxgCzgXzgMyghDgCIYBnAWjDRgFMoA7UgbgCh36mBXEgFUzAmAc34BPMPUTs4cAGIBJAEoBlfgBpZcVQFEAwgHkAcgBF2OTsIZR8KdNPnAoFGIOEiZcmJPoAuOHdRCSkAOiU1fg5LdmtGOwcdenQIJgATIM8EbR8pAMyQ+lC9IzNozlzpTLgAXgVnV2qAHySU9MyOdjTkgBsUKGk21zh4fKFRTtQMTAAKGABKbVCAd2AYWaRKsY9C8JV1XA0CWoA+OCGIHqKeiBEZ0nwGmFJ5xbkVtY2R323g32KDCZTIdjjUzhcrqEbndSBRkqk0i83nBQvQAB6YFA8VzAABu9Bm8w4QA

Workaround Defining the enum values as string fixes the problem. Defining them as number (explicitly), doesn't.

With string: https://www.typescriptlang.org/play?target=9&jsx=0&module=7#code/JYWwDg9gTgLgBAbziAhjAxgCzgXzgMyghDgCIYBnAWjDRgFMoA7UgbgCh36mBXEgFUzAmAc34BPMPUTs4cAGIBJAEoBlfnAC8ZJWv4B9fgAlFAOQDihgJoAFAKKkANLLiq7AYQDypgCJaybl6+hiYW1vak7DicwgxQ+Cjo0vLAUBQwgsIiMnIwkvQAXHCZohJSAHS66hzR7LGMCUmu9OgQTAAmJdkILnlSRV1l9OWB3j41nH3SXf4paRlConAAPs2tHV0c7O0tADYoUNLr6XDwA4siW6gYmAAUMACULuUA7sAwd0hT51lDlSrqXCOAhaAB8cGOEF2w12EBEt1I+FS6VIDyecle70+p3yP1K+RGHjGQJBmnBkOh5Vh8NIFBabXaqPRcHK9AAHpgUDx0sAAG70W4PDhAA

Versions

Somewhat offtopic

This library is impressive! Thanks for building it.

mattstyles commented 1 year ago

Looks like a duplicate of #168.

See also #58 and #162.

Link to underlying ts bug/issue/defect/whatever https://github.com/microsoft/TypeScript/issues/46562

alcuadrado commented 1 year ago

Thanks! That's correct.

What about adding a "Limitations" section to the readme? This is really surprising.

I understand it's a TS limitation, but it must be hitting many (potential) users.

edumt commented 10 months ago

if you can't simply migrate to a string enum, there's a "dirty" (typesafe) workaround using numbers, just explicitly cast the enum value

match(t)
  .with({ type: ThingType.FIRST as 0 }, f => console.log("first"))
  .with({ type: ThingType.SECOND as 1 }, f => console.log("second"))
  .exhaustive();
leebenson commented 5 days ago

What about adding a "Limitations" section to the readme? This is really surprising.

I think this would be hugely beneficial. I'm not sure it's common knowledge that numeric enums are quite so permissive/dangerous in Typescript. The thumbs up on your comment confirms it.

Even though this isn't a ts-pattern problem per se, I'd bet exhaustive checking of basic enums is one of the most obvious use-cases. Coming from Rust or other functional languages with pattern matching, this is really going to trip people up.

A few words in the README would go a long way.

Thanks for the great lib!