ts-pattern
ts-pattern copied to clipboard
when() guard with the ability to select() if true
Is your feature request related to a problem? Please describe.
First of all, if this is already possible I'm going to apologize in advance. I've only recently discovered your library, and I think it is absolutely incredible. As a strong functional programming advocate who also works in TypeScript a lot, this is one of those missing pieces that I have been waiting for.
Describe the solution you'd like
The when() guard is extremely helpful, especially when working with types from the fp-ts library. The following example uses fp-ts/Option, which has sub-types of Some or None.
match(some)
.with(when(O.isSome), (theSome) => console.log('Some', theSome.value))
.with(when(O.isNone), () => console.log('None'))
.run();
This is all well and good, but as you can see above the Some type has an additional property called "value". While there are multiple ways to select this property, one of which you see above, it would be nice to be able to use your select() function on it as well.
Based on all the documentation I've gone through so far, there appears to be no way to combine the when() and some() functions into a single expression. This is disappointing.
Describe alternatives you've considered
I have looked at multiple pattern matching libraries for TypeScript, and so far I'm liking yours most of all. This issue is not a dealbreaker for me, I'm more hoping that I've just missed something in your docs.
Additional context
I want to emphasize what a wonderful job you have done with this library. It is a truly excellent addition to the TypeScript world. I can see how much you have done, and how much you continue to actively do. Thank you for your excellent work.
👋
Indeed there is no way to combine a when
and a select
together at the moment, sorry about that.
That said, you don't have to use a when
guard with fp-ts, because you can pattern match on the object shape directly, which means you can use it with select
like this:
import { match, select } from "ts-pattern";
import * as O from "fp-ts/Option";
const res = match(O.some("hello"))
.with({ _tag: "Some", value: select() }, (value) => value)
.with({ _tag: "None" }, () => "")
.exhaustive();
console.log(res);
// => "hello"
Also, if logical operators for patterns as suggested in #61 were supported, then you could and
together a when
and a select
and that would solve this problem, but I'm not sure yet if this will be added to the lib.
👋 Thanks for the library and the workaround @gvergnaud 😊
As I was looking into adopting ts-pattern
I also was wondering how to export matchers for types like Option
or Result
so that people don't have to retype the same pattern every time.
Currently, as you said, the issue can be solved in place thanks to P.intersection()
:
type MyEither = Either<{tag: "errorOne", foo: string} | {tag: "errorTwo", bar: number}, string>;
match(either)
.when(P.intersection({_tag: "Right"}, {value: P.select()}), (val) => console.log(`val : ${val}`))
.when(P.intersection({_tag: "Left"}, {error: P.select({tag: "errorOne"})), (error) => console.log(`Foo is: ${error.foo}`))
.when(P.intersection({_tag: "Right"}, {error: P.select({tag: "errorTwo"})}, (error) => console.log(`Bar is: ${error.bar}`))
Ergonomically, it would be great if we could define matchRight
and matchLeft
such as we can do:
match(either)
.when(matchRight(), (val) => console.log(`val : ${val}`))
.when(matchLeft({tag: "errorOne"}), (error) => console.log(`Foo is: ${error.foo}`))
.when(matchLeft({tag: "errorTwo"}), (error) => console.log(`Bar is: ${error.bar}`))
I imagine that the typing of such functions might not be easy to do (I actually tried 😄 ), but it would be a great improvement for such use cases.
@GabeAtWork I think this is what you are looking for https://github.com/gvergnaud/ts-pattern/issues/137#issuecomment-1398138849
@gvergnaud at first glance it looks like it, yes! I'll give it a try 😊 Thank you for taking the time to review my comment 🙏