Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.with and Pattern.not error since 4.1.3 #138

Closed
adrienharnay opened this issue Jan 20, 2023 · 7 comments
Closed

.with and Pattern.not error since 4.1.3 #138

adrienharnay opened this issue Jan 20, 2023 · 7 comments

Comments

@adrienharnay
Copy link

Describe the bug

Since 4.1.3, when using Pattern.not, the following branches will act as if Pattern.not was in fact Pattern.any. If narrowing in following branches cannot be done, then I would expect the contrary (no narrowing on Pattern.not usages).

Code Sandbox with a minimal reproduction case
https://codesandbox.io/s/typescript-playground-export-forked-48dyon?file=/index.ts

Versions

  • TypeScript version: 4.9.4
  • ts-pattern version: 4.1.3
  • environment: Node 18.11.0

Thanks in advance!

@gvergnaud
Copy link
Owner

gvergnaud commented Jan 21, 2023

Thanks definitely a bug, I'll take a look shortly

@gvergnaud
Copy link
Owner

I had a look and it turns out it's incredibly difficult to solve without breaking exhaustive checking for not patterns. It would be much simpler if TypeScript had Negated Types but it unfortunately doesn't.

In the meantime, the best workaround is to use P.not after other cases:

import { match, Pattern } from "ts-pattern";

type Input = { type: "video"; seconds: number };

let input = ({ type: "user", name: "Gabriel" } as unknown) as Input;

const output = match(input)
  .with({ type: "video", seconds: 10 }, () => "video of 10 seconds.")
  // Swapped these 👆👇
  .with(
    { type: "video", seconds: Pattern.not(10) },
    () => "not video of 10 seconds."
  )
  .otherwise(() => "something else");

@adrienharnay
Copy link
Author

Ah... That's a shame. The replication is a very simple example of my real code, which looks like this:

match(object)
.with({ __typename: 'Something', conflicts: Pattern.not([]) }, () => 0)
.with({ __typename: 'Something', updated_at: Pattern.string }, () => 1)
...

Any idea how to replace Pattern.not([])?

@gvergnaud
Copy link
Owner

Yes, you could use P.when(xs => xs.length > 0)

@adrienharnay
Copy link
Author

Ah yes, of course! Thank you. Maybe it would make sense to update the docs for Pattern.not to mention this breaks narrowing in following branches?

@gvergnaud
Copy link
Owner

Hey, I found a way to fix this issue in the end. It's not perfect but it solve your use case, see details in the release note: https://github.com/gvergnaud/ts-pattern/releases/tag/v4.1.4

@jasikpark
Copy link

thx for fixing this, sucks that negated types can't be used but it's cool to see this library develop -- I hope for the day we get rust-esque exhaustive match { } value blocks in TS / JS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants