TypeScript React 应用程序中的 PropTypes

IT技术 reactjs typescript react-proptypes
2021-04-01 00:46:18

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

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

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

添加有什么真正的好处吗

static propTypes {
    myProp: React.PropTypes.string
}

到类定义?

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,这样您就不必两次指定类型,例如:

“Typescript 和 PropTypes 有不同的用途。Typescript 在编译时验证类型,而 PropTypes 在运行时检查。” --- 编译时和运行时没有不同的目的它们是出于相同目的而不同的种类,编译时间更优。
2021-05-24 00:46:18
这是关于如何从 PropTypes 推断静态类型的一个很好的解释:dev.to/busypeoples/...
2021-05-25 00:46:18
@Julia,热重载与运行时没有任何共同之处。即使使用热重载,您也不知道 api 将真正返回什么
2021-06-06 00:46:18
propTypes 和 Typescript 类型是否容易不同步?有没有人有维修经验告诉我们?
2021-06-16 00:46:18
这是正确答案!PropTypes(运行时)与静态类型检查(编译时)不同。因此,同时使用两者并不是“毫无意义的练习”。
2021-06-21 00:46:18

同时将组件 props 维护为 TypeScript 类型通常没有太大valueReact.PropTypes

以下是一些有用的情况:

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

因此,通常问题是您可以信任您的编译时验证。

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

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

正如@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;
这似乎是一个很好的解决方案,请您解释一下从道具类型推断typescript类型是否有任何问题,谢谢(我对typescript很陌生)
2021-05-22 00:46:18
@maroofshittu 我一直在我严格的 TS 项目中使用它,并且工作正常,包括复杂的场景。
2021-05-23 00:46:18

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

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

除此之外,我真的没有看到任何好处(这就是为什么我从来没有亲自使用过它)。

PropTypes 验证对于验证动态加载的数据结构(通过 AJAX 来自服务器)也很有意义。PropTypes 是运行时验证,因此可以真正帮助调试东西。因为问题会输出清晰且人性化的信息。
2021-05-24 00:46:18

我最近在桥接本机代码时使用了 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)
      }
    }
}