Reputation: 32304
Does using React.PropTypes
make sense in a TypeScript React Application or is this just a case of "belt and suspenders"?
Since the component class is declared with a Props
type parameter:
interface Props {
// ...
}
export class MyComponent extends React.Component<Props, any> { ... }
is there any real benefit to adding
static propTypes {
myProp: React.PropTypes.string
}
to the class definition?
Upvotes: 249
Views: 151730
Reputation: 2894
I recently used Proptypes and TS when bridging native code. The project is written in TypeScript on the React side, and I abstract away my native component on the React side in its own file. There was no need for worrying about PropTypes had this not been in its own file since I am already validating the data via TypeScript.
The PropTypes are used to handle external data coming in from Swift on an event callback. I tried using TypeScript here instead of PropTypes, but I was having issues with referencing the React components.
Ultimately, it was easier to implement PropTypes and doesn't seem to have drawbacks, since data validation at runtime worked perfectly fine.
Please refer to the code here for more detail:
//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],
);
};
}
And on the native side:
//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
as well as...
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)
}
}
}
Upvotes: 0
Reputation: 71
"InferPropTypes" from @types/prop-types can be used to create type definitions from PropTypes definitions. check the below example
import React from "react";
import PropTypes, { InferProps } from "prop-types";
const ComponentPropTypes = {
title: PropTypes.string.isRequired,
createdAt: PropTypes.instanceOf(Date),
authorName: PropTypes.string.isRequired,
};
type ComponentTypes = InferProps<typeof ComponentPropTypes>;
const MyComponent = ({ authorName, createdAt, title }: ComponentTypes) => {
return <span>Blog Card</span>;
};
MyComponent.propTypes = ComponentPropTypes;
export default MyComponent;
Upvotes: 6
Reputation: 25162
As @afonsoduarte said.
I'd just add that you can also generate Typescript types from PropTypes like this:
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;
Upvotes: 39
Reputation: 74695
I guess that in some messy situations where the type of the props can't be inferred at compile time, then it would be useful to see any warnings generated from using propTypes
at run time.
One such situation would be when processing data from an external source for which type definitions are not available, such as an external API beyond your control. For internal APIs, I think that is worth the effort to write (or better, generate) type definitions, if they are not already available.
Other than that, I don't really see any benefit (which I why I've never used it personally).
Upvotes: 8
Reputation: 1956
There's usually not much value to maintaining both your component props as TypeScript types and React.PropTypes
at the same time.
Here are some cases where it is useful to do so:
So, usually it's a question of how much you can trust your compile time validation.
Newer versions of TypeScript can now infer types based on your React.PropTypes
(PropTypes.InferProps
), but the resulting types can be difficult to use or refer to elsewhere in your code.
Upvotes: 166
Reputation: 12038
Typescript and PropTypes serve different purposes. Typescript validates types at compile time, whereas PropTypes are checked at runtime.
Typescript is useful when you are writing code: it will warn you if you pass an argument of the wrong type to your React components, give you autocomplete for function calls, etc.
PropTypes are useful when you test how the components interact with external data, for example when you load JSON from an API. PropTypes will help you debug (when in React's Development mode) why your component is failing by printing helpful messages like:
Warning: Failed prop type: Invalid prop `id` of type `number` supplied to `Table`, expected `string`
Even though it may seem like Typescript and PropTypes do the same thing, they don't actually overlap at all. But it is possible to automatically generate PropTypes from Typescript so that you don't have to specify types twice, see for example:
Upvotes: 346