React redux typescript: connect has missing type error
This how I do it in a Typescript Redux App (adjusted to your code but not tested)
edited with comment below
type
connect
with props for the Connected Component (ConnectedHelloWorldProps
)const ConnectedHelloWorld:React.ComponentClass<ConnectedHelloWorldProps> = connect<any,any,HelloWorldProps>(mapStateToProps)(HelloWorld) interface ConnectedHelloWorldProps { } interface HelloWorldProps extends ConnectedHelloWorldProps { count: number .... }
use the connected component and its
ConnectedHelloWorldProps
props in theProvider
<Provider store={store}> <ConnectedHelloWorld/> </Provider>
Note: this works fine with these typings
"@types/react": "^0.14.52",
"@types/react-dom": "^0.14.19",
"@types/react-redux": "^4.4.35",
"@types/redux-thunk": "^2.1.32",
ConnectedHellowWorldProps
is not really needed here, since it is an empty interface, but in a real world scenario it is likely to contain a few props.
The basic principle is this: ConnectedHelloWorldProps
contain what needs to be passed at the Provider level. In mapStateToProps
and/or mapDispatchToProps
, enrich the actual Component HelloWorldProps
with whatever is needed
Redux Typescript typings are a beast but what is shown above should be sufficient.
export declare function connect<TStateProps, TDispatchProps, TOwnProps>(
mapStateToProps: FuncOrSelf<MapStateToProps<TStateProps, TOwnProps>>,
mapDispatchToProps?: FuncOrSelf<MapDispatchToPropsFunction<TDispatchProps, TOwnProps> | MapDispatchToPropsObject>): ComponentDecorator<TStateProps & TDispatchProps, TOwnProps>;
interface ComponentDecorator<TOriginalProps, TOwnProps> {
(component: ComponentClass<TOriginalProps> | StatelessComponent<TOriginalProps>): ComponentClass<TOwnProps>;
}
Your problem is that HelloWorldState
is defined like this
interface HelloWorldState {
clickCount: number
}
And the props you want to return from mapStateToProps
are
{
count: state.clickCount
}
But you override the return-type as HelloWorldState
, so the return type does not contain count
but clickCount
.
fromJS
breaks type safety
ImmutableJS.fromJS
works pretty bad with TypeScript type inference:
const state = Immutable.fromJS({
count: 0
})
Here state
is of type any
so you don't have any error when assigning it as a return value of type HelloWorldState
.
mapStateToProps
should return a simple object
mapStateToProps
can return a simple object, as you won't directly edit this state from the component:
const mapStateToProps = (state: AppState): HelloWorldState => {
return {
count: state.clickCount
}
}
Here you will have the error you did not have when using ImmutableJS, telling you that you cannot assign { count: number }
to { clickCount: number }
.
So just remove the return type, and type-inference will do the job, or add the correct type.
const mapStateToProps = (state: AppState) => {
return {
count: state.clickCount
}
}
Statically-typed tree structural-sharing with Monolite
I also recommend you to use Monolite which is a simple set of functions written in TypeScript and designed to be used with Redux states.
It allows you to also define your state with simple JavaScript objects, and to make updates on the state through simple functions.
import { set } from 'monolite'
const state = {
clickCount: 0
}
const newState = set(state, _ => _.clickCount)(value => value + 1)
P.S. I'm the author of Monolite