【问题标题】:PropTypes in a TypeScript React ApplicationTypeScript React 应用程序中的 PropTypes
【发布时间】:2017-06-04 09:39:11
【问题描述】:

在 TypeScript React 应用程序中使用 React.PropTypes 是否有意义,或者这只是“腰带和吊带”的情况?

由于组件类是用Props 类型参数声明的:

interface Props {
    // ...
}
export class MyComponent extends React.Component<Props, any> { ... }

添加有什么真正的好处

static propTypes {
    myProp: React.PropTypes.string
}

到类定义?

【问题讨论】:

    标签: reactjs typescript react-proptypes


    【解决方案1】:

    我最近在桥接本机代码时使用了 Proptypes 和 TS。该项目是在 React 端用 TypeScript 编写的,我将 React 端的本机组件抽象到它自己的文件中。如果 PropTypes 不在其自己的文件中,则无需担心,因为我已经通过 TypeScript 验证数据。

    PropTypes 用于在事件回调中处理来自 Swift 的外部数据。我在这里尝试使用 TypeScript 而不是 PropTypes,但在引用 React 组件时遇到了问题。

    最终,PropTypes 更容易实现并且似乎没有缺点,因为运行时的数据验证工作得非常好。

    详情请参考这里的代码:

    //CoreView.js
    import React, {Component} from 'react';
    import PropTypes from 'prop-types';
    
    import {requireNativeComponent, UIManager, findNodeHandle} from 'react-native';
    
    const COMPONENT_NAME = 'CoreView';
    const RNCoreView = requireNativeComponent(COMPONENT_NAME);
    
    export default class CoreView extends Component {
      static propTypes = {
        label: PropTypes.array,
        onUpdate: PropTypes.func,
      };
      _onUpdate = event => {
        if (this.props.onUpdate) {
          this.props.onUpdate(event.nativeEvent);
        }
      };
      render() {
        const {label, style} = this.props;
        return (
          <RNCoreView
            style={style}
            label={label}
            onUpdate={this._onUpdate}
            ref={ref => (this.ref = ref)}
          />
        );
      }
      update = (...args) => {
        UIManager.dispatchViewManagerCommand(
          findNodeHandle(this.ref),
          UIManager[COMPONENT_NAME].Commands.obtainLabelData,
          [...args],
        );
      };
    }
    

    在 Swift 方面:

    //CoreViewManager.m
    #import <Foundation/Foundation.h>
    
    #import "React/RCTViewManager.h"
    @interface RCT_EXTERN_MODULE(CoreViewManager, RCTViewManager)
    
    //Allow React to send data as props
    RCT_EXPORT_VIEW_PROPERTY(onUpdate, RCTDirectEventBlock)
    
    RCT_EXTERN_METHOD(
      obtainLabelData:(nonnull NSNumber *)node
      imageLocation:(nonnull NSString *)imageLocation
    )
    
    @end
    

    还有……

    import Foundation
    
    @available(iOS 11.0, *)
    @objc(CoreViewManager)
    class CoreViewManager: RCTViewManager {
      override func view() -> UIView! {
        return CoreView()
      }
      
      @objc func obtainLabelData(_ node: NSNumber, imageLocation: NSString!) {
          
          DispatchQueue.main.async {
            let component = self.bridge.uiManager.view(
              forReactTag: node
            ) as! CoreView
            component.update(value: imageLocation)
          }
        }
    }
    

    【讨论】:

      【解决方案2】:

      正如@afonsoduarte 所说。

      我想补充一点,你也可以像这样从 PropTypes 生成 Typescript 类型:

      const propTypes = {
        input: PropTypes.shape({
          id: PropTypes.number.isRequired,
          name: PropTypes.string.isRequired,
        }),
      };
      
      type MyComponentProps = PropTypes.InferProps<typeof propTypes>;
      
      const MyComponent: FunctionComponent<MyComponentProps > = (props) => {
        // ...
      }
      
      MyComponent.propTypes = propTypes;
      

      【讨论】:

      • 这似乎是一个很好的解决方案,您能否解释一下从道具类型推断打字稿类型是否有任何问题,如果有的话,谢谢(我对打字稿很陌生)
      • @maroofshittu 我一直在我严格的 TS 项目中使用它,并且工作正常,包括复杂的场景。
      【解决方案3】:

      我猜想在一些无法在编译时推断道具类型的混乱情况下,查看在运行时使用propTypes 生成的任何警告会很有用。

      其中一种情况是在处理来自类型定义不可用的外部源的数据时,例如您无法控制的外部 API。对于内部 API,如果它们尚不可用,我认为编写(或更好地生成)类型定义是值得的。

      除此之外,我并没有真正看到任何好处(这就是我从未亲自使用过它的原因)。

      【讨论】:

      • PropTypes 验证对于验证动态加载的数据结构(通过 AJAX 来自服务器)也很有意义。 PropTypes 是运行时验证,因此可以真正帮助调试东西。因为问题会输出清晰且人性化的消息。
      【解决方案4】:

      将组件属性同时维护为 TypeScript 类型和 React.PropTypes 通常没有太大价值。

      以下是一些有用的情况:

      • 发布将由纯 JavaScript 使用的组件库等包。
      • 接受并传递外部输入,例如 API 调用的结果。
      • 使用来自可能没有足够或准确类型的库中的数据(如果有)。

      因此,通常这是一个问题,即您可以在多大程度上信任您的编译时验证。

      较新版本的 TypeScript 现在可以根据您的 React.PropTypes (PropTypes.InferProps) 推断类型,但生成的类型可能难以在代码中的其他地方使用或引用。

      【讨论】:

      • 你能解释一下第一句话吗?
      • @vehsakul 抱歉,澄清一下,如果您正在编写一个将由不使用 TypeScript 的开发人员安装的包,他们仍然需要 PropTypes 才能在运行时获取错误。如果您的项目仅适用于您自己/其他 TypeScript 项目,那么您的道具的 TypeScript 接口就足够了,因为该项目根本不会构建。
      • 这是一个在 Webpack 级别从 typescript 接口添加 PropTypes 的 POC github.com/grncdr/ts-react-loader#what-it-does
      • 我想要一个 oneOfType -- optionalUnion: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.instanceOf(Message) ]), -- typescript 有联合类型,但它们没有给我同样的东西
      • 我也发布了一个库:github.com/joelday/ts-proptypes-transformer 它被实现为 TypeScript 编译器转换,它为深度泛型、联合等生成准确的 propTypes。有一些粗糙的边缘,所以任何贡献都会很棒。
      【解决方案5】:

      Typescript 和 PropTypes 有不同的用途。 Typescript 在编译时验证类型,而 PropTypes 在运行时检查。

      Typescript 在您编写代码时很有用:如果您将错误类型的参数传递给您的 React 组件,它会发出警告,为您提供函数调用的自动完成功能等。

      当您测试组件如何与外部数据交互时,PropTypes 很有用,例如当您从 API 加载 JSON 时。 PropTypes 将通过打印有用的消息来帮助您调试(在 React 的开发模式下)您的组件失败的原因:

      Warning: Failed prop type: Invalid prop `id` of type `number` supplied to `Table`, expected `string`
      

      尽管看起来 Typescript 和 PropTypes 做同样的事情,但它们实际上并没有重叠。但是可以从 Typescript 自动生成 PropTypes,这样您就不必指定类型两次,例如:

      【讨论】:

      • propTypes 和 Typescript 类型容易不同步吗?有没有人有维修经验告诉我们?
      • 这是正确答案! PropTypes(运行时)与静态类型检查(编译时)不同。因此,同时使用两者并不是“毫无意义的练习”。
      • 这里很好地解释了如何从 PropTypes 中推断出静态类型:dev.to/busypeoples/…
      • @Julia,热重载与运行时没有任何共同之处。即使使用热重载,您也不知道 api 将真正返回什么
      • "Typescript 和 PropTypes 有不同的用途。Typescript 在编译时验证类型,而 PropTypes 在运行时检查。" --- 编译时和运行时不是不同的用途。为了相同的目的,它们是不同的类型,而且编译时间更优越。
      猜你喜欢
      • 2020-10-31
      • 1970-01-01
      • 2019-11-29
      • 2019-07-01
      • 2019-06-01
      • 2017-10-01
      • 2020-10-15
      • 2017-12-29
      相关资源
      最近更新 更多