It seems like the type annotation for react-redux’s connect
is not compatible with the recompose’s HOC
type declaration. I often encountered errors when connect
is specified in compose
function like this:
const enhance: HOC<*, Props> = compose(
connect(),
pure, // <-- Flow error - Component: This type is incompatible with the expected param type of Component
withHandlers({
...
})
)
If I removed connect()
from parameters, the flow error disappears. Huh? But the app with this code works fine so I guess there are some bugs in the Flow-typed definitions. I don’t wanna waste time for this problem.
So I made simple utility functions to make connect
compatible with compose
function which yet prop type inference is working in base components. Below code is getDispatch
function that calls connect
with no parameters so it will simply add dispatch
to props
of the base component:
// @flow
import { type HOC } from 'recompose'
import { connect } from 'react-redux'
import type { Dispatch } from '../types'
type CHOC<E: {}> = HOC<{ ...$Exact<E>, dispatch: Dispatch }, E>
export default function getDispatch<Enhanced: {}>(): CHOC<Enhanced> {
return (connect(): Function)
}
You can use it like so:
const enhance: HOC<*, Props> = compose(
withDispatch(),
pure,
withHandlers({
...
})
)
And you will get props.dispatch
.
When you want to get store mapped to props, you can use below connectStore
function:
// @flow
import { type HOC } from 'recompose'
import { connect } from 'react-redux'
import type { Dispatch, State } from '../types'
type F<M> = (state: State) => M
type CHOC<E: {}, M> = HOC<{ ...$Exact<E>, dispatch: Dispatch, ...M }, E>
export default function connectStore<Enhanced: {}, M: *>(
mapper: F<M>
): CHOC<Enhanced, M> {
return (connect(mapper): Function)
}
It forces the type of connector function casted as recompose’s HOC
so it will work without problem:
const enhance: HOC<*, Props> = compose(
connect(({ editingNote }) => ({ editingNote })),
pure,
withHandlers({
...
})
)
const EnhancedComponent = enhance(props => {
console.log(props.editingNote) // <-- type inference works!
})
Obviously it is just a workaround and it even may break in the future, but it simplifies my codebase and works fine for now.
The type inference in Flow is pretty great but type annotations tend to be very complicated. It reminds me of the macro hell in C/C++ 🙄
Top comments (0)