maybe
maybe copied to clipboard
Flowtype and .filter()
I have been looking at the maybe source code and trying to work out how to improve the typing of the .filter() method but I haven't worked anything out. The problem is below. Is it possible to fix this within maybe or is flow not able to handle this anyway yet?
maybe(getUserType()) // => 'admin' | 'customer'
.filter(userType => userType !== 'admin')
.forEach((userType: 'customer') => // => flow complains that userType is 'admin' | 'customer'
doSomethingOnlyCustomerCanDo(userType)
)
Hi @Leeds-eBooks,
The problem is that filter returns the same type A as wrapped in Maybe (in this case the union of 'admin' | 'customer'.
Essentially what you want is to restrict the type, but you probably don't need to. I would suggest allowing the doSomething() function to allow either type and just have this runtime validation with maybe.filter.
Alternatively you may want to look at type aliases, or classes to represent your user objects instead.
Thanks!
Also conceptually, filter shouldn't change the value of A. What you're after is actually similar to Scala's collect() which is like filter and map combined.
What about:
.flatMap(userType => userType !== 'admin' ? just(userType) : nothing)
It looks a bit janky but it would solve your type problem.
@maartenschumacher That works a treat, thanks so much.
@alexanderjarvis would it make sense to add this method to maybe? I mean something like:
collect(p: (A) => boolean): Maybe<B> {
if (p(this.value)) {
return just(this.value)
} else {
return nothing
}
}
That's probably all wrong but just for illustrative purposes.
How would you define B? What you're trying to do is refine the type, for which Flow does have some internal representations: https://github.com/facebook/flow/blob/dd0603e9d8c9d5fb99a40f0b179a4d6a2b9e66b7/tests/predicates-abstract/refine.js
But the question is if this stuff will ever be exposed in a nice way