Add autocomplete to Typescript/React component - reactjs

I have a component (typescript + react) which I published on NPM. I want to make IntelliSense autocomplete React props for this component for me. For plain react components I used js doc, but it doesn't work here.
example of component:
class MyComp extends React.Component<
MyCompPropsInterface,
MyCompComponentState
> {...}
index file
import { MyComp } from './components/MyComp ';
export { MyComp };
If I missed something please point it and I will add it.

So I found the problem, I didn't pass my interface to the constructor.
How it should be:
class MyComp extends React.Component<
MyCompPropsInterface,
MyCompComponentState
> {
constructor(
public props: ImagePropsInterface,
)
}

Related

How to extend React Component prop typing without changing all usages of React.Component

I want to make testID a prop available for all React.Component instances for native testing. Currently, I am adding it to prop type of all the components that are using it. Is there any way where, for example I can define react/index.d.ts and override the Component prop type to include {testID?: string}?
EDIT:
// types/react/index.d.ts
import 'react'
import { Attributes, ClassAttributes } from 'react'
declare namespace react {
interface IntrinsicAttributes extends Attributes {
testID?: string
}
interface IntrinsicClassAttributes<T> extends ClassAttributes<T> {
testID?: string
}
}
I tried the above override, but it's not working, but if I copy the whole react typing file in and then make above changes, it works fine. So I just need proper overriding technique. Can someone please help me in that?
// src/types/react/index.d.ts
import * as React from 'react'
declare global {
namespace JSX {
interface IntrinsicAttributes extends React.Attributes {
testID?: string
}
interface IntrinsicClassAttributes<T> extends React.ClassAttributes<T> {
testID?: string
}
}
}
Above override worked for me. Thanks all!
For class components, create a proxy class and extend it as even static properties are inherited :
class Proxy extends React.Component {
static propTypes = {
testId: PropTypes.string
};
}
class SomeComponent extends Proxy {
render() {
}
}
For functional components, you cannot do this. An alternative would be to create a utility which will add it for you :
function withPropTypes(Component) {
Component.propTypes = {
testId : PropTypes.string
};
return Component;
}
function SomeComponent() {
}
const SomeComponentWithPropTypes = withProps(SomeComponent);
Note: You can use the above util for class components also.

Passing Typescript generics on React component through connect from react-redux

I'm trying to use generics in a component that gets passed through react-redux's connect. Here's a stripped down version:
export default class ItemBar<T> extends React.PureComponent{
// ...
}
When I use ItemBar with no connect, it looks like this:
export default class Component extends React.PureComponent {
render() {
return <ItemBar<number> />;
}
}
This works properly. When I "connect" the ItemBar class as such:
class ItemBar<T> extends React.PureComponent {
// ...
}
export default connect()(ItemBar);
I now get Expected 0 type arguments, but got 1. from Typescript. I think this is because the connect (and probably any other higher component) doesn't pass through the generics. Is there any way I can get this to work?
class ItemBar<T> extends React.PureComponent {
// ...
}
const connected = connect()(ItemBar);
export class ItemBar<T> extends connected {}
You may have to disable tslint at last line if you have one class rule per file.

WebStorm type checking React props using type definition

I'm using WebStorm 2018.3.4 and am trying to figure out how to do type checking on a React component's props. Specifically, if a prop is marked as a string but I give it a number I want WebStorm to show an error. I've created a type definition file (as described here). Here's what the file looks like:
MyComponent.d.ts
import * as React from 'react';
export interface MyComponentProps {
/** this is the component's title */
title: string;
/** this is a short description of the component */
description?: string;
}
declare class MyComponent extends React.Component<MyComponentProps, {}> {
render(): JSX.Element;
}
export default MyComponent;
App.jsx
class App extends React.Component {
render() {
return (
<MyComponent title={7} />
);
}
}
I was hoping WebStorm would underline title={7} telling me that 7 is the wrong type. If I Ctrl+Q on the prop it definitely tells me the type is string and it gives me the documentation from the .d.ts file. Is there a setting I need to enable? Or does WebStorm not support this? Or is my problem that my app is using JSX rather than TypeScript? Any help would be appreciated.
You can install prop-types
Then you can write your component like this:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class App extends Component {
static propTypes = {
userId: PropTypes.string.isRequired,
someObject: PropTypes.object.isRequired,
someFunction: PropTypes.func.isRequired,
};
render() {
....
}
}

In reactjs, what is wrappedComponent.propTypes?

Below code example is a simplified version a component. I don't understand the code at the bottom of this component, the Case.wrappedComponent.propTypes part. I can't find relevant document about wrappedComponent on Internet as well.
Questions:
What is wrappedComponent and propTypes key in it?
What do they do?
Where can I find document for these things?
import React, { Component } from 'react';
#inject('store') #observer
export default class Case extends Component {
constructor(props) {
super(props);
this.caseId = this.props.match.params.id;
this.setOtherComment = this.setOtherComment.bind(this)
this.submitOtherComment = this.submitOtherComment.bind(this)
}
render() {
return '...'
}
}
Case.wrappedComponent.propTypes = {
store: React.PropTypes.object.isRequired,
match: React.PropTypes.object.isRequired
};
This is an API of mobx-react (with inject) and according to the DOCS
Using propTypes and defaultProps and other static properties in combination with inject
Inject wraps a new component around the component you pass into it. This means that assigning a static property to the resulting component, will be applied to the HoC, and not to the original component
........
if you want to make assertions on the data that is being injected
(either stores or data resulting from a mapper function), the
propTypes should be defined on the wrapped component. Which is
available through the static property wrappedComponent on the inject
component

TypeScript Property 'props' does not exist

I have this .tsx file:
import React, { Component } from 'react';
export class SidebarItem extends Component {
constructor(props) {
super(props);
}
render() {
return (<li>{this.props.children}</li>);
}
}
However, TypeScript throws this error:
error TS2339: Property 'props' does not exist on type 'SidebarItem'.
The solution is to install the React Types defintions
yarn add -DE #types/react
More details from the typescript docs and from the types repo
On a side note I had to restart vscode for the linting to kick in properly.
TypeScript follows the ES-module specification but React follows CommonJS.
This article touches on that among other things.
Importing React like this will fix this problem:
import * as React from 'react';
export class SidebarItem extends React.Component {
constructor (props) {
super(props);
}
render () {
return (<li>{this.props.children}</li>);
}
}
You can try the following way of writing a React Comp.
interface SidebarItemProps
{
children: any
}
class SidebarItem extends React.Component<SidebarItemProps, any> {
//your class methods
}
More about using React in TypeScript
If your component has no state, you don't have to use a class at all. You can also use a stateless react component (SFC) as answered for this question.
const MyStatelessComponent : React.StatelessComponent<{}> = props =>
<li>{props.children}</li>;
Or if your markup is getting huge:
const MyStatelessComponent : React.StatelessComponent<{}> = props => {
return <li>{props.children}</li>;
}

Resources