react-router-dom with TypeScript

2020-05-14 05:00发布

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);

7条回答
看我几分像从前
2楼-- · 2020-05-14 05:30

It looks like you have the right usage to apply the match, history, and location props to your component. I would check in your node_modules directory to see what versions of react-router and react-router-dom you have, as well as the @types modules.

I have essentially the same code as you, and mine is working with the following versions:

{
  "@types/react-router-dom": "^4.0.4",
  "react-router-dom": "^4.1.1",
}
查看更多
Anthone
3楼-- · 2020-05-14 05:37

This is a Typescript typings issue. Since withRouter() will provide the routing props you need at runtime, you want to tell consumers that they only need to specify the other props. In this case, you could just use a plain ComponentClass:

export default withRouter(connectModule) as React.ComponentClass<{}>;

Or, if you had other props (defined in an interface called OwnProps) you wanted to pass in, you could do this:

export default withRouter(connectModule) as React.ComponentClass<OwnProps>;

There is slightly more discussion here

查看更多
等我变得足够好
4楼-- · 2020-05-14 05:41

The way how I'm doing this:

interface IOwnProps {
  style?: CSSProperties;
}

interface INavProps {
  item?: string;
}

type IProps = IOwnProps & RouteComponentProps<INavProps>;

export default class MapScreen extends PureComponent<IProps> {
  ...
}
查看更多
在下西门庆
5楼-- · 2020-05-14 05:42

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

interface HomeProps extends RouteComponentProps<any>, React.Props<any> {
}
查看更多
ら.Afraid
6楼-- · 2020-05-14 05:44

After browsing the typescript definitions I discovered the RouteComponentProps interface so I now model my containers like so

type RouteParams = {
    teamId: string; // must be type string since route params
}

interface Props extends RouteComponentProps<RouteParams>, React.Props<RouteParams> { }

type State = {
    players: Array<Player>;
}

export class PlayersContainer extends React.Component<Props, State>{} 

now in the component class the route props can be accessed like this: let teamid = this.props.match.params.teamId;

查看更多
做自己的国王
7楼-- · 2020-05-14 05:45

+1 for Ramon's answer. You can absolutely get full type coverage here. To add a bit - I added the call to withRouter.

interface FooProps extends RouteComponentProps<Foo> {
  foo: string;
}

const Foo = ({ history, foo }: FooProps) => <span/>;

const RoutedFoo = withRouter(Foo);

my dependencies:

"@types/react-router-dom": "^4.3.0",
"typescript": "^2.9.2",
查看更多
登录 后发表回答