ts-pattern icon indicating copy to clipboard operation
ts-pattern copied to clipboard

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

Open alcuadrado opened this issue 2 years ago • 5 comments

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

  • TypeScript version: 5.1.6
  • ts-pattern version: 5.0.4
  • environment: node 20.5.0, ts's playground, and anything I tried.

Somewhat offtopic

This library is impressive! Thanks for building it.

alcuadrado avatar Jul 23 '23 15:07 alcuadrado

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

mattstyles avatar Jul 26 '23 14:07 mattstyles

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.

alcuadrado avatar Jul 26 '23 22:07 alcuadrado

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();

edumt avatar Jan 09 '24 20:01 edumt