gvergnaud / ts-pattern

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

Set exhaustive not working on type level? #189

Closed darky closed 1 year ago

darky commented 1 year ago

Describe the bug Trying to exhaustive Set, but seems it's not working on type level

Code Sandbox with a minimal reproduction case

const s = new Set<'a' | 'b'>(['a']);

match(s)
  .with(P.set('a'), () => 123)
  .with(P.set('b'), () => 123)
  .exhaustive();

// This expression is not callable.
//  Type 'NonExhaustiveError<Set<"a" | "b">>' has no call signatures.ts(2349)

Versions

darrylnoakes commented 1 year ago

First, Set<'a' | 'b'> means that each of the Set's elements must satisfy 'a' | 'b', not that the whole Set must satisfy only one of them. For example, Set<number | string> is a Set of numbers and strings.

Second, P.set(subpattern) only matches if all the elements match the sub pattern. Because of this, you have handled the case of a Set with the value 'a' and a Set with the value 'b', not the case of a Set with both.

Depending what you're trying to achieve, you could add the case for both, using a ts-pattern union. However, the possibilities explode exponentially as you add more potential elements. Or, you could change the declaration of the Set to const s: Set<'a'> | Set<'b'> = new Set(['a']). This of course limits you to a Set with only one element, which doesn't make much sense.

This seems like a very contrived example (and possibly an XY problem), so I'm not sure what exactly you're actually trying to achieve.

TypeScript Playground