如何将 PropTypes.shape 与 Typescript 一起使用

Thi*_*ddi 10 types typescript reactjs react-proptypes

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

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;
Run Code Online (Sandbox Code Playgroud)

但我在 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>'
Run Code Online (Sandbox Code Playgroud)

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

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>'
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

所以我的问题是如何使嵌套的 PropTypes 对象(PropTypes.shape()或者可能PropTypes.objectOf())与 TypeScript 一起使用?

Nic*_*uño 8

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

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

例如:

Footer.propTypes = {
  labels: PropTypes.exact({
    body: PropTypes.string
  }).isRequired
};
Run Code Online (Sandbox Code Playgroud)

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

属性“body”在类型“InferProps<{ body: Validator;”中是可选的 }>' 但在“FooterLabels”类型中是必需的。ts(2322)

编辑

发生这种情况只是因为您在组件上使用 const Footer: React.FC<FooterProps> = ({ labels }) => (

FC(功能组件接口)查看接口表示为

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

这里我们应该强调的一行是propTypes?: WeakValidationMap<P>;This 行,它根据我们的 PropTypes 推断出我们的类型。

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

例如 function Footer = ({ labels }:FooterProps): ReactNode => (


kin*_*ser 1

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

interface FooterProps {
  labels: {
     body: FooterLabels;
  };
}
Run Code Online (Sandbox Code Playgroud)