How to use TypeScript with withRouter, connect, React.Component and custom properties?
How I do it in our projects (this is the easiest way and you can get intellisense when you use it):
import * as React from 'react'import { connect } from 'react-redux';import { withRouter, RouteComponentProps } from 'react-router';import { fetchTestLists, newTestList, displayTestList,} from '../../../actions/index';interface StateProps { testList: any; // todo: use the type of state.myList to have validation on it}interface DispatchProps { fetchTestLists: () => void; newTestList: () => void; displayTestList: (any) => void; // todo: replace any with the actual type}interface Props extends RouteComponentProps { // custom properties passed to component className: string;}type PropsType = StateProps & DispatchProps & Props;class MyTest extends React.Component<PropsType> { constructor(props) { super(props); this.handleCellClick = this.handleCellClick.bind(this); this.newTestList = this.newTestList.bind(this); } componentDidMount() { this.props.fetchTestLists(); } handleCellClick(row, column, event) { this.props.displayTestList(row); } newTestList(e) { this.props.newTestList() } render() { return ( <div className={this.props.className}> </div> ); }}const mapStateToProps = (state, ownProps: Props): StateProps => ({ testList: state.myList, // todo: define a type for the root state to have validation here});const dispatchToProps: DispatchProps = { fetchTestLists, newTestList, displayTestList,};export default withRouter(connect( mapStateToProps, dispatchToProps,)(MyTest));
Also if this is something you will type often I recommend writing a custom snippet (if you are using something like VS Code it is very easy).
I try to rewrite your example and end up with this code:
import * as React from 'react';import { connect } from 'react-redux';import { RouteComponentProps, withRouter } from 'react-router';import { fetchTestLists, newTestList, displayTestList,} from '../../../actions/index';import { Dispatch, bindActionCreators, AnyAction } from 'redux';interface IStateProps { testList: IListType; // todo: use the type of state.myList to have validation on it}interface IDispatchProps { fetchTestLists: () => AnyAction; newTestList: () => AnyAction; displayTestList: (value: string) => AnyAction; // todo: replace any with the actual type}interface IProps { // custom properties passed to component className: string;}type PropsType = IStateProps & IDispatchProps & IProps;class MyTestComponent extends React.Component<PropsType & RouteComponentProps<{}>, {}> { constructor(props: PropsType & RouteComponentProps<{}>) { super(props); this.handleCellClick = this.handleCellClick.bind(this); this.newTestList = this.newTestList.bind(this); } public componentDidMount() { this.props.fetchTestLists(); } public handleCellClick(row, column, event) { this.props.displayTestList(row); } public newTestList(e) { this.props.newTestList(); } public render(): JSX.Element { return ( <div className={this.props.className}> </div> ); }}export const MyTest = connect( (state: IAppState, ownProps: IProps) => ({ testList: state.testList, ...ownProps, }), (dispatch: Dispatch) => bindActionCreators<AnyAction, Pick<IDispatchProps, keyof IDispatchProps>>( { displayTestList, fetchTestLists, newTestList }, dispatch,),)(withRouter(MyTestComponent));interface IListType { someProp: string;}interface IAppState { testList: IListType; differentList: IListType;}
I have changed export default on to assigning result of wrapped MyTestComponent class with connect and withRouter HOC into MyTest. Then I import MyTest component like this
import { MyTest } from './MyTest'
I have added interfaces to describe all properties which have been passed from Parent component, also use withRouter and connect in different way (more readable for me).
I hope it will be helpful
I solved this issue by forcing an install of the @types/react-redux package. I had just updated from 4.4.5 to 5.0.15.
It might be worth while to run a fresh npm install --save @types/react-redux@5.0.15
.