React Router - Typescript errors on withRouter after updating version

59,302

Solution 1

I just upgraded to TypeScript 2.6 and got same issue.

I managed to resolve it by using RouteComponentProps.

For URL http://localhost:8080/your-component/abc and route

<Route component={YourComponent} path="/your-component/:param1?" />

Component should look like this:

import * as React from 'react'
import { withRouter } from 'react-router-dom';
import {RouteComponentProps} from "react-router";

// Type whatever you expect in 'this.props.match.params.*'
type PathParamsType = {
    param1: string,
}

// Your component own properties
type PropsType = RouteComponentProps<PathParamsType> & {
    someString: string,
}

class YourComponent extends React.Component<PropsType> {
    render() {

        console.log(this.props); // Prints all props including routing-related
        console.log(this.props.match.params.param1); // Prints 'abc'
        console.log(typeof this.props.match.params.param1 === 'string'); // prints 'true'

        return <div>...</div>;
    }
}

export default withRouter(YourComponent);

Solution 2

I have to solve it like this:

import * as React from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';

interface IProps extends RouteComponentProps<any> {
  title: string;
}

class MyComp extends React.Component<IProps> {
    public render(){
        return (
           <h1>{this.props.title}</h1>
        )
    }
}

export default withRouter<IProps>(MyComp);

Solution 3

Here's a functional react approach I use

import { RouteComponentProps } from "react-router";

interface Props extends RouteComponentProps {
    thing: Thing | false;
    onAction?: () => void;
}

export default withRouter(({ thing, onAction, history }: Props) => {

Solution 4

Here is how I usually strucutre my typed React components:

// These props are provided when creating the component
interface OwnProps {
    // ...
}

// These props are provided via connecting the component to the store
interface StateProps {
    // ...
}

// These props are provided by the router
interface PathProps {
    // ...
}

class Component extends React.Component<OwnProps & StateProps & RouteComponentProps<PathProps>> {
    // ...
}

const mapStateToProps = (state: State, props: OwnProps): StateProps => ({
    // ...
});

export default withRouter(
    connect(mapStateToProps)(Component)
);

Solution 5

Another solution, using decorators

import { withRouter, RouteComponentProps } from "react-router";

// inform we match url /:id
interface IMatchParams {
    id: string;
}

// Note we use Partial<RouteComponentProps> to make all RouteComponentProps as optional for high order component
interface IComponentProps extends Partial<RouteComponentProps<IMatchParams>> {
    myPersonalProp: string;
}

@withRouter
export default class MyClass extends React.Component<IComponentProps>{

    public componentDidMount(){
        console.log(this.props.match.params.id);
    }
}
Share:
59,302
29er
Author by

29er

Updated on July 08, 2022

Comments

  • 29er
    29er almost 2 years

    I just tried to upgrade my React app to

    react-router - 4.0.19 to 4.0.20

    react- 16.0.30 to 16.0.34

    typescript- version "2.7.0-insiders.20180108"

    In my app, wherever I am using 'withRouter', I now get cryptic Typescript errors. I even replaced all interface props with 'any' just to try to make it work.

    import * as React from 'react';
    import { Switch, Route, withRouter} from 'react-router-dom';
    import { Login } from './Login';
    import { connect } from 'react-redux';
    import { RootAction, RootState } from './_redux';
    
    class MainForm extends React.Component<any> {
    
      constructor(props: any) {
        super(props);
      }
    
      render() {
    
        return (
          <Switch>
            <Route exact={true} path="/" component={Login}/>
            <Route  path="/accounts" component={AccountsView}/>
          </Switch> 
        );
      }
    }
    
    const mapStateToProps = (state: RootState) => ({
      state
    });
    
    export const Main = withRouter(connect(mapStateToProps)(MainForm);
    

    error TS2345: Argument of type 'ComponentClass> & { WrappedComponent: ComponentType; }' is not assignable to parameter of type 'ComponentType>'. Type 'ComponentClass> & { WrappedComponent: ComponentType; }' is not assignable to type 'StatelessComponent>'. Type 'ComponentClass> & { WrappedComponent: ComponentType; }' provides no match for the signature '(props: RouteComponentProps & { children?: ReactNode; }, context?: any): ReactElement | null'.

    If i convert the last line to this :

    export const Main = connect(mapStateToProps)(MainForm);
    

    I don't get errors. seriously frustrated here. Thanks

    EDIT, I changed to

    export const Main = connect(mapStateToProps)(withRouter(MainForm));
    

    like suggested by Mayank Shukla. but now get the error:

    error TS2345: Argument of type 'ComponentClass>' is not assignable to parameter of type 'ComponentType<{ state: RootState; } & DispatchProp>'. Type 'ComponentClass>' is not assignable to type 'StatelessComponent<{ state: RootState; } & DispatchProp>'. Type 'ComponentClass>' provides no match for the signature '(props: { state: RootState; } & DispatchProp & { children?: ReactNode; }, context?: any): ReactElement | null'.