facebook / facebook/flow

Unions of objects and their properties

Open
#4,299 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
22.3k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

I'm wondering why in flow unions of objects don't match unions of the types within objects. For example:

```
type ActionObject = {| type: 'a' |} | {| type: 'b' |}
type ActionTypesInObject = {| type: 'a' | 'b' |}

const func1 = (arg: 'a' | 'b'): ActionTypesInObject => {
return {
type: arg
}
}

const func2 = (arg: 'a' | 'b'): ActionObject => {
return {
type: arg
}
}
```

func1 works as expected, func2 gives the error that This type is incompatible in the return value ([try flow link](https://flow.org/try/#0C4TwDgpgBAggxsAlgewHYHkBGArCCDOUAvFAN4A+UokAXFAOQCG9U5Avq2ZdRHfZi3YAoHrAQpUAFXAR8ASQw48wYlyoy+zTv0FshQuGnwqAZgFdUcAIyqAFIwBOAc02CGAgJR14SNNMjyirgIxAB8ZEJQUA4QwGYOqBFRUTx0jk6RUHp6BkamFnAATHbprtqe3uJoWMHAhEThpJkxcQlJyalQ6ZnZQA)).

(It seems like potentially something like the `$UnionMap` operator [that has been proposed](https://github.com/facebook/flow/issues/3350) would be useful to avoid duplication in writing these two related types, but I imagine it wouldn't change the behavior).

Is the issue that this would require backtracking or trying different branches [as described here](https://flow.org/blog/2016/07/01/New-Unions-Intersections/)? And if so would it be possible to add this behavior?

My use case is that I was hoping to do something more complicated with combinations of arguments, but was surprised to see that even reducing to the above simpler example doesn't work. What I really want to do is in the context of redux, I would like to type all of my actions and be able to write a generic function that creates an action where the constraints on the parameters need to depend on each other. For example:

```
type ActionObject2 = {| type: 'a', data: 1 |} | {| type: 'b', data: 2 |}

function createAction(typeArg: A, dataArg: D): ActionObject2 {
return { type: typeArg, data: dataArg }
}

createAction('a', 1) // Should work
createAction('b', 2) // Should work
createAction('a', 2) // Should fail, would cause an invalid return function
```

(In this simple example I could rewrite so I'm passing in the object instead of separate args, but more realistically I might be calling the function with typeArg but the dataArg comes from somewhere else like resolving a promise of type `Promise<1>`).

Related issues:
- https://github.com/facebook/flow/issues/2892
- https://github.com/facebook/flow/issues/3929
- https://github.com/facebook/flow/issues/3350

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.