gvergnaud / ts-pattern

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

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

Open BenLorantfy-AB opened 4 months ago

BenLorantfy-AB commented 4 months ago

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

gvergnaud commented 4 months ago

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