gvergnaud/ts-pattern

`.exhaustive()` does not cause TS error when using `instanceOf`

BenLorantfy-AB opened this issue · 1 comments

Describe the bug
The exhaustive() function does not raise a TS error when instanceOf is used and not all possible classes are handled

TypeScript playground with a minimal reproduction case

Example: Playground

In the above example, I would expect that exhaustive() to raise a NonExhaustiveError error because ClassB is not handled

Versions

  • TypeScript version: 5.4.5
  • ts-pattern version: 4.0.1

This is unfortunately a limitation from the TypeScript type system – structural typing makes it consider two classes with different names as the same type, unless they contain a discriminant property to distinguish them.

class ClassA {}
class ClassB {}

type T = Exclude<ClassA | ClassB, ClassA>
//   ^? never

In this case, you could expect T to be of type ClassB, but it isn't.

One workaround is to give them a discriminant property:

class ClassA {
   type = "ClassA" as const
}

class ClassB {
   type = "ClassB" as const
}

let err2: ClassA | ClassB = new ClassB();

const result2 = match(err2)
   .with(P.instanceOf(ClassA), (result) => "classA")
   .exhaustive(); // ❌

Playground