As announced in this blog post, Flow 0.85 needs extra type annotations for some exports.
This seems to be the case for react-redux connected components.
Here is an example:
https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVBLAtgBzgJwBdkwBDAZzACUBTUgY2KnzizAHJ87H2BudYMDDlsOGBigYaAEzBcGhALRdpAVwAeYQgE8cNcumk16MUly26aYACIZyOUoXoALAIIAFAJIAeVwD4wAF4wAAoFDDgAOwAuMFcASiCA134jEzMrHT0bOwcnZ19YgG8smliAEgBlVQAjUu9yQnwMSIBzPwBfAODbe0cXDx9-flQ003NSsABZUhxKwkcaABU4dxYccm9K2IB5GoArY0IAGjBK912Do9Oqc8vDxm7QxsXYytOcdfI390TAgNu7hGYwyYCgqkijAikTA9CikSO3lQYDAAGFWLFaAoAHTo3BRGiRQhLSzeEB+Y7Is73a5Uu5gPYPE5UwE0xiUlGoi5gcq2KBQbxYxjYgCiMBoWEJhHRkUkrW8eIp1HOFLpS2KAG0APoVADSNG0m0VAF1YqRItoOqg-CEqVhZvNFis1nANrEZnMFoRlqsvltTucbiqOWB7ThenkXM6vgB+WKRVQwGCoeKxEJw-EIomxPF-AHcQi41h4LPE0lcsAAMjO7gC1aqzlmNC2Sz8I0EYEJsjgUDkBeUMg0Fj0BnQkxdGyCYCKAB8qTh46osDUaPgQy0mTJuQnl6vUDOOiM4ZFGmjiwSiVPQkUcKcN0ctx1YhPyHnQlTvNIMAA3Pw3jpkJEshFPejCPt4wBfr+YApugx6nmGjretGrqUMEIRviERRUqB3rSNyADMqAdPER5RKeMoImB0h4jgU7HlRhAhIhXo+i+8QhLRF6EKR6AhBhSTvii3h+FSwlcaWYA4IERQAIwAbhW4yQATABwCiSi4nwg+NHFlJMnyWA6kfsZ8QcfE6A0OoeBEGARhQKQibEJROm0fwmkeZ5XneWAQA
It fails with these two errors in Flow 0.85, but worked fine in Flow 0.84
Missing type annotation for `CP`. `CP` is a type parameter declared in function type [1] and was implicitly instantiated at call of `connect` [2].
and
Missing type annotation for `SP`. `SP` is a type parameter declared in function type [1] and was implicitly instantiated at call of `connect` [2]
So what's the recommended way to type connected components with react-redux and Flow 0.85?
Not sure if I should open an issue to flow-typed instead
See my response to this question on the Medium post.
The simplest thing is to add an explicit type argument to the call of connect
, which is at the location pointed to by the error message in your example. The specific types you provide depend on the signature of the function.
I suspect that the flow-typed folks might want to rework the type declarations to make it simpler to provide these annotations. I suggested one approach in my comment on Medium. The details of the specific declaration should be taken up with the author, so I suspect that a question to the flow-typed repo would be a good step.
@samwgoldman, thanks a bunch for providing those concise and strict typings for connect
I personally was missing forever!
Imho, there is a little typo in the typings:
- mapStateToProps: MapStateToProps<S, OP, DP>,
+ mapStateToProps: MapStateToProps<S, OP, SP>,
- mapDispatchToProps: MapDispatchToProps<D, OP, SP>,
+ mapDispatchToProps: MapDispatchToProps<D, OP, DP>,
This fixes an error like this:
[Flow] Cannot call
connect
withmapStateToProps
bound tomapStateToProps
because propertysomeDispatchProperty
is missing inStateProps
but exists inDispatchProps
[2] in the return value.
By the way, for those type hackers spending their weekends in fixing 100 new (legitimate) errors, here is how I use a bit modified version of Sam's typings.
First I split the huge all in one Props
type in three distinct types (OwnProps
, StateProps
, DispatchProps
) and one combined (just Props
):
// these are the old school props coming from component usage:
// <Component own1="foo" own2="bar" />
type OwnProps = {|
own1: string,
own2: number,
|};
// these are the props coming from state via `mapStateToProps`
type StateProps = {|
state1: boolean,
state2: number,
|};
// these are the props dispatching actions from `mapDispatchToProps`
type DispatchProps = {|
action1: typeof actionCreator1, // actionCreator1 is an imported action creator function
action2: typeof actionCreator2, // actionCreator2 is an imported action creator function
|};
// and finally the main type for component type creation (`Component<Props, …>`, see below)
type Props = {|
...OwnProps,
...StateProps,
...DispatchProps,
|};
// here is the normal React component class definition
class MyComponent extends Component<Props, void> {
render() {
// `this.props` has all the props as expected because it's of type `Props`
console.log(this.props.own1)
console.log(this.props.own2)
console.log(this.props.state1)
console.log(this.props.state2)
// including action dispatchers
console.log(this.props.action1(…))
console.log(this.props.action2(…))
}
}
// and the most important part is using the `connect()` function with proper type parameters
export const MyController = connect<State, Dispatch, OwnProps, StateProps, DispatchProps>(
mapStateToProps,
mapDispatchToProps,
)(MyComponent);
The State
and Dispatch
types come from how it's officially recommended to type Redux with Flow. In short:
// the overall state of your app
type State = {|
+forms: FormsReducerState,
+notifications: NotificationsReducerState,
// and so on
|}
// all the actions of your app
type Action = FormsAction1 | FormsAction2 | NotificationsAction1 | NotificationsAction2;
// type of a `dispatch()` function
type Dispatch = Action => Action
P.S. Adding this code to connect()
typings allows to use an object with dispatchers instead of a function:
+ declare export function connect<S, D, OP, SP, DP>(
+ mapStateToProps: MapStateToProps<S, OP, SP>,
+ mapDispatchToProps: DP,
+ ): Connector<S, D, OP, React$ComponentType<{| ...OP, ...SP, ...DP |}>>;
Notice, that I use a bit modified version of Sam's typings. Patches are welcome :)
EDIT: as stated in Sam's comment it is also possible to use _ type placeholder in place of StateProps
and DispatchProps
arguments in the call to connect()
to make Flow infer the types for you:
export const MyController = connect<State, Dispatch, OwnProps, _, _>(
mapStateToProps,
mapDispatchToProps,
)(MyComponent);
but his trick makes error messages a bit more verbose and possible make Flow less performant. Something like how it was with the Existential Type (*).
Whenever I think I'm starting to get flow, stuff like this breaks my brain 😅
I have no idea how to fix my 300 connect
errors right now. Giving them 6 parameters doesn't really sound like the most readable thing to do.
I wonder if the should be a way to tell Flow "I know what I'm doing" and make it possible to export a generic instantiation, like $FlowFixMe but for performance related things. Kinda $FlowTrustMe :D
My sad face when Flow is already at 0.88 but we can't get past 0.85 without $FlowFixMe-fying 500 errors...
This feels pretty bad. Why was this closed?
@oshalygin I guess, because of these two PRs to flow-typed
: https://github.com/flow-typed/flow-typed/pull/3012 and https://github.com/flow-typed/flow-typed/pull/3035, we continued the party there.
We are also crafting another one to make the connect()
function typings more composable with other HOC (in terms of compose()
function from Redux) here: https://github.com/flow-typed/flow-typed/pull/3076. Please, help 😊
Thanks for the update @peter-leonov !
@kangax As far as I understand it should be still possible to type via:
connect<*, *, *, *, *>
So I think, running replace of connect(
with connect<*, *, *, *, *>(
may solve part of your issues.
Most helpful comment
Whenever I think I'm starting to get flow, stuff like this breaks my brain 😅
I have no idea how to fix my 300
connect
errors right now. Giving them 6 parameters doesn't really sound like the most readable thing to do.