Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-router-dom with TypeScript

I'm trying to use react router with TypeScript. However, I have certain problems using withRouter function. On the last line, I'm getting pretty weird error:

Argument of type 'ComponentClass<{}>' is not assignable to parameter of type 'StatelessComponent<RouteComponentProps<any>> | ComponentClass<RouteComponentProps<any>>'.   Type 'ComponentClass<{}>' is not assignable to type 'ComponentClass<RouteComponentProps<any>>'.     Type '{}' is not assignable to type 'RouteComponentProps<any>'.       Property 'match' is missing in type '{}’ 

Code looks like:

import * as React from 'react'; import { connect } from 'react-redux'; import { RouteComponentProps, withRouter } from 'react-router-dom';  interface HomeProps extends RouteComponentProps<any> { }  interface HomeState { }  class Home extends React.Component<HomeProps, HomeState> {   constructor(props: HomeProps) {     super(props);   }   public render(): JSX.Element {     return (<span>Home</span>);   } }  const connectModule = connect(   (state) => ({     // Map state to props   }),   {     // Map dispatch to props   })(Home);  export default withRouter(connectModule); 
like image 588
Haris Bašić Avatar asked May 22 '17 16:05

Haris Bašić


People also ask

What is Router in Typescript?

Implementing React Router v6 with code splitting in a React Typescript project. React Router is a standard library for routing in React. It enables the navigation among views of various components in a React Application, allows changing the browser URL, and keeps the UI in sync with the URL.

Is react Router Dom deprecated?

This feature has been deprecated because the new structure of Routes is that they should act like components, so you should take advantage of component lifecycle methods instead.


2 Answers

I use a different approach to fix this. I always separate the different properties (router, regular and dispatch), so I define the following interfaces for my component:

interface HomeRouterProps {   title: string;   // This one is coming from the router }  interface HomeProps extends RouteComponentProps<HomeRouterProps> {   // Add your regular properties here }  interface HomeDispatchProps {   // Add your dispatcher properties here } 

You can now either create a new type that combines all properties in a single type, but I always combine the types during the component definition (I don't add the state here, but if you need one just go ahead). The component definition looks like this:

class Home extends React.Component<HomeProps & HomeDispatchProps> {   constructor(props: HomeProps & HomeDispatchProps) {     super(props);   }    public render() {     return (<span>{this.props.match.params.title}</span>);   } } 

Now we need to wire the component to the state via a container. It looks like this:

function mapStateToProps(state, ownProps: HomeProps): HomeProps => {   // Map state to props (add the properties after the spread)   return { ...ownProps }; }  function mapDispatchToProps(dispatch): HomeDispatchProps {   // Map dispatch to props   return {}; }  export default connect(mapStateToProps, mapDispatchToProps)(Hello); 

This method allows a fully typed connection, so the component and container are fully typed and it is safe to refactor it. The only thing that isn't safe for refactoring is the parameter in the route that is mapped to the HomeRouterProps interface.

like image 111
Ramon de Klein Avatar answered Sep 19 '22 18:09

Ramon de Klein


I think it is a typescript typings compilation issue, but I've found a workaround:

interface HomeProps extends RouteComponentProps<any>, React.Props<any> { } 
like image 25
carlosvin Avatar answered Sep 19 '22 18:09

carlosvin