maybe icon indicating copy to clipboard operation
maybe copied to clipboard

Flowtype and .filter()

Open benadamstyles opened this issue 8 years ago • 5 comments

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)
  )

benadamstyles avatar Apr 18 '17 08:04 benadamstyles

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!

alexanderjarvis avatar Apr 18 '17 11:04 alexanderjarvis

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.

alexanderjarvis avatar Apr 18 '17 11:04 alexanderjarvis

What about: .flatMap(userType => userType !== 'admin' ? just(userType) : nothing) It looks a bit janky but it would solve your type problem.

maartenschumacher avatar Apr 18 '17 11:04 maartenschumacher

@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.

benadamstyles avatar Apr 18 '17 13:04 benadamstyles

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

maartenschumacher avatar Apr 18 '17 17:04 maartenschumacher