【问题标题】:How to use PropTypes.shape with Typescript如何将 PropTypes.shape 与 Typescript 一起使用
【发布时间】:2020-04-04 23:20:24
【问题描述】:

我正在将 React 应用程序从 Javascript 重构为 Typescript,但在迁移时遇到了一些麻烦,尤其是 shape PropType。我的代码现在看起来像这样:

import React from 'react';
import PropTypes from 'prop-types';

interface FooterProps {
  labels: FooterLabels;
}

interface FooterLabels {
  body: string;
}

const Footer: React.FC<FooterProps> = ({ labels }) => (
  <div className="footer">
    {/* ... */}
  </div>
);

Footer.propTypes = {
  labels: PropTypes.shape({
    body: PropTypes.string.isRequired
  }).isRequired
};

export default Footer;

但我在 PropTypes 中遇到错误:

Type 'Validator<InferProps<{ body: Validator<string>; }>>' is not assignable to type 'Validator<FooterLabels>'.
  Type 'InferProps<{ body: Validator<string>; }>' is not assignable to type 'FooterLabels'.
    Property 'body' is optional in type 'InferProps<{ body: Validator<string>; }>' but required in type 'FooterLabels'.ts(2322)
FooterAppPromo.tsx(5, 3): The expected type comes from property 'labels' which is declared here on type 'WeakValidationMap<FooterProps>'

我是 Typescript 的新手,所以有时我真的不知道自己在做什么,但我尝试做以下事情:

Footer.propTypes = {
  labels: PropTypes.shape<FooterLabels>({
    body: PropTypes.string.isRequired
  }).isRequired
};

但我遇到了错误。我尝试搜索示例实现,但找不到。

编辑

Typescript 类型和 PropTypes 是一回事。您可以轻松编写一个 Typescript 验证通过但仍会收到 PropTypes 警告的示例(例如,一个返回数字的外部 API,其中应该是字符串)。这里有两篇文章解释了原因:

所以我的问题是如何使嵌套的 PropTypes 对象(PropTypes.shape()PropTypes.objectOf())与 TypeScript 一起工作?

【问题讨论】:

  • 我认为只有interfaceReact.FC&lt;FooterProps&gt; 就足够了。你不需要 propTypes 使用 Typescript 进行反应
  • @AnhNguyen 我会争辩说,如果您这样做,则只能使用组件的 TS 感知消费者。我也在寻找propTypes 的 TS 解决方案。现在,tsc 出现错误:Type 'undefined' is not assignable to type 'MetaType'.

标签: reactjs typescript types react-proptypes


【解决方案1】:

PropTypes 错误是因为您尝试使用PropType.shape,该形状允许您在形状上具有可选值,在这种情况下,您的界面是严格的,这意味着您没有任何类型的可选值值,而React.Validator 试图用你的接口推断你的类型,这会导致错误出现。

简单来说,如果您有一个带有非可选值的严格接口,那么您应该使用PropType.shape 而不是PropType.exact,这样可以防止错误。

例如:

Footer.propTypes = {
  labels: PropTypes.exact({
    body: PropTypes.string
  }).isRequired
};

因此,您的错误消息会出现

属性 'body' 在类型 'InferProps' 但在 'FooterLabels'.ts(2322) 类型中是必需的

已编辑

这只是因为您在组件上使用 const Footer: React.FC&lt;FooterProps&gt; = ({ labels }) =&gt; (

查看接口的 FC(FunctionComponent Interface)表示为

interface FunctionComponent<P = {}> {
        (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
        propTypes?: WeakValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        defaultProps?: Partial<P>;
        displayName?: string;
    }

我们应该在这里突出显示的行是propTypes?: WeakValidationMap&lt;P&gt;; 这是根据我们的 PropTypes 推断我们的类型的行。

你有第二个选择在 React 上使用类型,但我不推荐它,你可以使用 ReactNode 类型来代替 FC,但是你会失去你在 FC 接口类型推断上的推断。

例如 function Footer = ({ labels }:FooterProps): ReactNode =&gt; (

【讨论】:

    【解决方案2】:

    实际上,这里不需要propTypes - labels 只得到一个嵌套字段body,即typeof FooterLabels

    interface FooterProps {
      labels: {
         body: FooterLabels;
      };
    }
    

    【讨论】:

      【解决方案3】:
      interface FooterProps {
        labels: PropTypes.InferProps<{ body: string }>
      }
      

      【讨论】:

      • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常质量更高,更有可能吸引投票。
      猜你喜欢
      • 2020-04-16
      • 2019-03-19
      • 1970-01-01
      • 2020-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-22
      • 2014-08-10
      相关资源
      最近更新 更多