How would I go about creating a react router in Typescript?

Viewed 4523

In a normal react project my router would look like this

I would have my app wrapped in a Component , and then I would have this

<Switch>

<Route path="/login" render={(props) => <LoginPage login={this.login} authed={this.state.isAuthenticated} {...props} />} />
<Route path="/" render={(props) => this.props.history.push("/login")} />

</Switch>

But I dont know how to simulate something similar in typescript . I currently have this

const App: React.FunctionComponent = () => {
  return (
    <Router>
      <div className="main-content">
        <div>
          <Switch>
            <Route exactly component={Main} exact pattern="/" />
            <Route exactly component={Count} exact pattern="/count" />
          </Switch>
        </div>
      </div>
    </Router>
  );
};

But it always redirects to main component. How could I do that an undefined route like /randomroute , would redirect to "/" , and how would I make the alternative route /count work?

EDIT: I have progressed a bit

import React from "react";
import { BrowserRouter as Router, Route, Switch, RouteComponentProps, RouteProps } from "react-router-dom";
import Main from "./components/Main";
import Count from "./components/Count"
import "./App.css";

interface ChildComponentProps extends RouteProps {
  /* other props for ChildComponent */
}

const App: React.FunctionComponent<ChildComponentProps> = (props) => {
  return (
    <Router>
      <div className="main-content">
        <div>
          <Switch>
            <Route exactly component={Main} exact path="/" />
            <Route exactly component={Count} exact path="/count" />
            <Route pattern ="/" render={() => props.history.push("/") } />
          </Switch>
        </div>
      </div>
    </Router>
  );
};

export default App;

Problem now is that, history is inside the RouteComponentProps interface, while RouteProps interface contains render, and I cant use them at the same time, so im a bit lost

EDIT2: Trying this

   interface RenderProps extends RouteProps {
  /* other props for ChildComponent */
}
interface HistoryProps extends RouteComponentProps {

}

const App: React.FunctionComponent<HistoryProps & RenderProps>

Receiving in render

The expected type comes from property 'render' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<Route> & Readonly & Readonly<...>'

When supposedly that interface is imported

Edit4:

I did this

import React from "react";
import { BrowserRouter as Router, Route, Switch, RouteComponentProps, RouteProps, withRouter  } from "react-router-dom";
import Main from "./components/Main";
import Count from "./components/Count"
import "./App.css";

interface RenderProps extends RouteProps {
  /* other props for ChildComponent */
}
interface HistoryProps extends RouteComponentProps {
    
}

const App: React.FunctionComponent<RenderProps & HistoryProps> = (props) => {
  return (
      <div className="main-content">
        <div>
          <Switch>
            <Route exactly component={Main} exact path="/" />
            <Route exactly component={Count} exact path="/count" />
            <Route path ="/" {...props.history.push("/")} />
          </Switch>
        </div>
      </div>
  );
};


export default withRouter(App);

And wrapper the app component in index.tsx file into (browserouter)

Now im getting a

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops

Because of the props.history.push

1 Answers

I ended up doing this, but im waiting for better answers

import React from "react";
import { Route, Switch, RouteComponentProps, withRouter} from "react-router-dom";
import Main from "./components/Main";
import Count from "./components/Count";
import Redirector from "./components/Redirect"
import "./App.css";


interface HistoryProps extends RouteComponentProps {
    
}


const App: React.FunctionComponent<HistoryProps> = (props) => {
  return (
      <div className="main-content">
        <div>
          <Switch>
            <Route exactly component={Main} exact path="/" />
            <Route exactly component={Count} exact path="/count" />
            <Route path ="/" exactly component={Redirector}/>
          </Switch>
        </div>
      </div>
  );
};


export default withRouter(App);

Redirect.tsx

import * as React from "react";
import { Redirect   } from "react-router-dom";

const Redirector: React.FunctionComponent = () => {
  
  return <Redirect to='/'/>;
};

export default Redirector

EDIT2: Probably a better approach

import React from "react";
import { Route, Switch, withRouter, Redirect} from "react-router-dom";
import Main from "./components/Main";
import Count from "./components/Count";
import "./App.css";


const App: React.FunctionComponent = () => {
  const renderFor404Routes = () => (<Redirect to='/'/>);
  return (
      <div className="main-content">
        <div>
          <Switch>
            <Route exactly component={Main} exact path="/" />
            <Route exactly component={Count} exact path="/count" />
            <Route path ="/" exactly component={renderFor404Routes}/>
          </Switch>
        </div>
      </div>
  );
};

export default withRouter(App);
Related