gvergnaud / ts-pattern

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

Does not seem to resolve discriminated unions correctly #235

Closed ian-schu closed 8 months ago

ian-schu commented 8 months ago

Describe the bug Love this library and have enjoyed adopting it across our codebase 👍🏻

Today I'm trying to use ts-pattern to handle a discriminated union type, and within each with statement it looks like the type is NOT resolved correctly. I played with this a few different ways, and found that a native switch statement does exactly what I want, but ts-pattern does not.

Hopefully this is just user error, maybe I'm getting something subtly wrong with the match API.

Code Sandbox with a minimal reproduction case Once the language server finishes loading on this example, you'll see compiler warnings on the ts-pattern attempt at this problem, whereas the native switch version has no problems.

https://codesandbox.io/p/sandbox/ts-pattern-discriminated-union-psqjrl?file=%2Fsrc%2Findex.ts%3A63%2C3

Versions

JUSTIVE commented 8 months ago

you should use narrowed instances to benefit from pattern matching.


match(object)
    .with({type:"variant1"}, (object) => {
      console.log(object.data.someField);
      console.log(object.flavor);
    })
    .with({type:"variant2"}, (object) => {
      console.log(object.data.length);
      console.log(object.kind);
    })
    .exhaustive();
};
gvergnaud commented 8 months ago

Yes, as @JUSTIVE showed, you need to match on the whole object and use the narrowed reference that's provided as a parameter to handler functions.

I wish there was a way to narrow an object that's in scope based on the pattern given to .with, but it isn't possible today.

JUSTIVE commented 7 months ago

maybe there's some point where we could benefit from typescript 5.5's type predicate inference. not sure how we'll benefit from it, but since it automatically narrows type, I'm pretty sure there's some way.

ian-schu commented 7 months ago

Thanks guys! I had no idea I was supposed to be matching on the whole object. It's interesting that the native TS switch will do this exactly as I hoped 🤔

Anyway, I am unblocked on this 👍🏻

Really interested in the TS 5.5 predicate inference. Seems like that would allow match() to behave a lot more like the native switch that I gave in my sandbox.