使用TypeScript的react-router-dom

问题描述 投票:45回答:7

我正在尝试使用TypeScript的react路由器。 但是,我在使用withRouter功能时遇到了一些问题。 在最后一行,我得到了非常奇怪的错误:

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 '{}’

代码如下:

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);
reactjs react-router react-router-redux react-router-v4
7个回答
45
投票

我使用不同的方法来解决这个问题。 我总是将不同的属性(路由器,常规和分派)分开,所以我为我的组件定义了以下接口:

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
}

您现在可以创建一个将单个类型中的所有属性组合在一起的新类型,但我总是在组件定义期间组合这些类型(我不在这里添加状态,但如果您需要一个,请继续)。 组件定义如下所示:

class Home extends React.Component<HomeProps & HomeDispatchProps> {
  constructor(props: HomeProps & HomeDispatchProps) {
    super(props);
  }

  public render() {
    return (<span>{this.props.match.params.title}</span>);
  }
}

现在我们需要通过容器将组件连接到状态。 它看起来像这样:

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

此方法允许完全类型化连接,因此组件和容器是完全类型的,并且可以安全地重构它。 唯一不安全的重构是路由中映射到HomeRouterProps接口的参数。


15
投票

我认为这是打字稿打字编译问题,但我找到了一个解决方法:

interface HomeProps extends RouteComponentProps<any>, React.Props<any> {
}

6
投票

这是一个Typescript打字问题。 由于withRouter()将在运行时提供您需要的路由道具,因此您希望告诉消费者他们只需要指定其他道具。 在这种情况下,您可以使用普通的ComponentClass:

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

或者,如果你想传入其他道具(在名为OwnProps的界面中定义),你可以这样做:

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

有稍微的讨论在这里


4
投票

看起来您有正确的用法将匹配,历史记录和位置道具应用于您的组件。 我会检查你的node_modules目录,看看你有哪些版本的react-routerreact-router-dom ,以及@types模块。

我和你的代码基本相同,我的代码使用以下版本:

{
  "@types/react-router-dom": "^4.0.4",
  "react-router-dom": "^4.1.1",
}

3
投票

在浏览了打字稿定义后,我发现了RouteComponentProps界面,所以我现在就像这样建模我的容器

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>{} 

现在在组件类中,可以像这样访问路径道具: let teamid = this.props.match.params.teamId;


1
投票

我这样做的方式:

interface IOwnProps {
  style?: CSSProperties;
}

interface INavProps {
  item?: string;
}

type IProps = IOwnProps & RouteComponentProps<INavProps>;

export default class MapScreen extends PureComponent<IProps> {
  ...
}

0
投票

拉蒙的回答是+1。 你绝对可以在这里获得完整的类型。 添加一点 - 我添加了对withRouter的调用。

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

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

const RoutedFoo = withRouter(Foo);

我的依赖:

"@types/react-router-dom": "^4.3.0",
"typescript": "^2.9.2",
© www.soinside.com 2019 - 2024. All rights reserved.