使用“ withRouter”和Typescript时类型出现问题

时间:2019-07-10 21:39:59

标签: typescript react-router react-router-dom

我正在尝试对React + Typescript进行更深入的了解和实践,使用withRouter中的react-router-dom时遇到了这种键入错误。

我的代码段非常简单,我试图找出存在相同问题的人员,并且一些答案指出升级时出错(但它们来自2016年,所以...),还有一些他们使用的是我不使用的connect()语句(这引发了一个问题:“由于不使用它,我做错了吗?”)。我看到其中一些建议还涉及将“ Props”映射到“ State”,到目前为止,我还没有做过(也没有看到)。我希望有人对我所缺少的内容以及应该关注的内容提出一些建议。

代码是:

import React from "react";
import { withRouter } from "react-router-dom";

interface ISection {
  id: number;
  title: string;
  imageUrl: string;
  size: string;
}

class MenuItem extends React.Component<ISection> {
  render() {
    return (
      <div className={`${this.props.size} menu-item`}>
        <div
          className="background-image"
          style={{ backgroundImage: `url(${this.props.imageUrl})` }}
        />
        <div className="content">
          <h1 className="title">{this.props.title}</h1>
          <span className="subtitle">some subtitle</span>
        </div>
      </div>
    );
  }
}

export default withRouter(MenuItem);

我期望从这里开始可以平稳地工作(我不得不说,我首先尝试了一个功能组件,因为我没有任何状态,但是我看到的所有解决方案都涉及一个类组件,所以我搬走了它),但我在最后一行的MenuItem上收到以下错误:

Argument of type 'typeof MenuItem' is not assignable to parameter of type 'ComponentClass<RouteComponentProps<any, StaticContext, any>, any> | FunctionComponent<RouteComponentProps<any, StaticContext, any>> | (FunctionComponent<RouteComponentProps<any, StaticContext, any>> & ComponentClass<...>) | (ComponentClass<...> & FunctionComponent<...>)'.
  Type 'typeof MenuItem' is not assignable to type 'ComponentClass<RouteComponentProps<any, StaticContext, any>, any>'.
    Types of parameters 'props' and 'props' are incompatible.
      Type 'RouteComponentProps<any, StaticContext, any>' is missing the following properties from type 'Readonly<ISection>': id, title, imageUrl, sizets(2345)

我的问题是:

  1. 为什么会说“ type'typeof MenuItem'”?

  2. 难道不是只说'MenuItem'的类型,而不是说要获取类型的函数吗?
  3. withRouter是否必须使用类组件,或者也可以使用功能组件?

  4. 我需要connect(),还是将道具映射到State?如果是这样,为什么?

  5. 最后,我该如何解决?

2 个答案:

答案 0 :(得分:1)

对于任何来这里使用 Next.js 的人来说,像这样将你的道具界面与 WithRouterProps 相交..

import { WithRouterProps } from "next/dist/client/with-router";

class MenuItem extends React.Component<IProps & WithRouterProps>

答案 1 :(得分:0)

documentation开始,withRouter将在渲染时将更新的matchlocationhistory道具传递给包装的组件。

因此MenuItem组件应具有道具来接收它们。目前,MenuItem组件具有类型ISection的道具,其中不包括路由器道具。

添加路由器道具的最简单方法是将ISectionRouteComponentProps相交。

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

// ...
class MenuItem extends React.Component<ISection & RouteComponentProps> {

完整代码是

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

interface ISection {
    id: number;
    title: string;
    imageUrl: string;
    size: string;
}

class MenuItem extends React.Component<ISection & RouteComponentProps> {
    render() {
        return (
            <div className={`${this.props.size} menu-item`}>
                <div
                    className="background-image"
                    style={{ backgroundImage: `url(${this.props.imageUrl})` }}
                />
                <div className="content">
                    <h1 className="title">{this.props.title}</h1>
                    <span className="subtitle">some subtitle</span>
                </div>
            </div>
        );
    }
}

export default withRouter(MenuItem);

以及您问题的答案

  1. 为什么会说“ type'typeof MenuItem'”?难道不是只说'MenuItem'的类型,而不是说获取类型的函数吗?

    由于类型不兼容而引起的错误。 MenuItem是类,不是类型。要获取MenuItem的类型,您应该使用typeof MenuItem。因此typeof MenuItem是类型。编译器正确地说“类型typeof MenuItem”。

  2. withRouter是否必须使用类组件,或者也可以使用功能组件?

    允许与类组件和功能组件一起使用。

    如果实现为功能,这就是您的组件的外观

    const Cmp1: React.FunctionComponent<ISection & RouteComponentProps> = (props) => {
        return (
            <div className={`${props.size} menu-item`}>
                <div
                    className="background-image"
                    style={{ backgroundImage: `url(${props.imageUrl})` }}
                />
                <div className="content">
                    <h1 className="title">{props.title}</h1>
                    <span className="subtitle">some subtitle</span>
                </div>
            </div>
        );
    }
    
    const WrappedCmp = withRouter(Cmp1);
    
  3. 我需要connect(),还是将道具映射到State?如果是这样,为什么?

    不,这不是严格的要求。 connect是Redux的一部分,因此,如果您使用Redux,则可以连接。这是documentationwithRouter一起使用connect的方法。但同样,它不是必需的。

  4. 最后,我该如何解决?

    已经回答。见上文:-)