TypeScript React应用程序中的PropTypes

时间:2017-01-19 15:45:55

标签: reactjs typescript react-proptypes

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

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

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

添加

有什么好处
static propTypes {
    myProp: React.PropTypes.string
}

到类定义?

5 个答案:

答案 0 :(得分:40)

如果要编写要由非TypeScript项目(例如组件库)使用的组件,那些项目仍然可以从基于PropTypes的类型验证中受益。

但是,如果您制作非TypeScript项目将要使用的任何东西,那么这是毫无意义的练习。现在尤其如此,TypeScript 2.4将支持JSX子类型检查(https://github.com/Microsoft/TypeScript/issues/13618)。

请注意,尽管context作为any提供,但仍需要contextTypes才能将这些值传递给您的组件。

我有兴趣看看是否有一个工具可以在编译时自动从TypeScript接口生成propTypes。那会非常酷。

答案 1 :(得分:10)

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

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

当您测试组件与外部数据的交互方式时,例如从API加载JSON时,

PropTypes很有用。 PropTypes将通过打印诸如以下的有用消息来帮助您调试(在React的开发模式下)组件失败的原因:

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

即使看上去Typescript和PropTypes做同样的事情,它们实际上也不重叠。但是可以从Typescript自动生成PropType,这样您就不必两次指定类型,例如:

答案 2 :(得分:6)

正如@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;

答案 3 :(得分:4)

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

除此之外,我没有看到任何好处(我为什么从未亲自使用过它)。

答案 4 :(得分:0)

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