TypeScript Property 'props' does not exist - reactjs

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>;
}

Related

Add autocomplete to Typescript/React component

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,
)
}

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.

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() {
....
}
}

Using a component defined in a .jsx file in a typescript file

We have purchased a react theme with the intent to use its component in our web application, and we ended up with some issues getting them to transpile, we got that solved. However, we're now running into issues with types.
I believe the issue here is that typescript doesn't like that props doesn't have a type defined on it and is defaulting to IntrinsicAttributes. I'd like to be able to use the components without modification.
The error:
(TS) Property 'content' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Card> & Readonly<{ children?: ReactNode; }> & Read...'
home.tsx
import * as React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import Card from './test';
type HomeProps = RouteComponentProps<{}>;
export default class Home extends React.Component<HomeProps, {}> {
public render() {
return <div>
<Card content="but why doesn't this work?" />
</div>
}
}
test.jsx
import React, { Component } from 'react';
class Card extends Component {
render() {
return <div>
{this.props.content}
</div>;
}
}
export default Card;
I think you are trying to create a new attribute, try creating a new interface for test file and define a interface in any of the typedefinition file as shown below,
interface Card {
content: any;
}
Thanks
React defaults props and state to have the type {}, and this is why it claims content does not exist in this example.
Perhaps better than implementing the interface for each component is to do the following trick (which is not the prettiest):
In the .tsx file:
import OriginalCard from './test';
/* tslint:disable */
const Card: any = OriginalCard;
/* tslint:enable */
And the you should be able to use Card without getting the error.

Click event in ReactJS error: imports/ui/ParentComponent.jsx:5:16: Unexpected token (5:16)

I am trying to learn Event in ReactJS.
I created 2 components
ChildComponent is
import React, { Component } from 'react';
// App component - represents the whole app
export default class ChildComponent extends Component {
render() {
return (
<button onClick={this.props.onBannerClick}>Click me!</button>
);
}
}
And ParentComponent is
import React, { Component } from 'react';
import ChildComponent from './ChildComponent.jsx'
// App component - represents the whole app
export default class ParentComponent extends Component {
performMagic: function() {
alert('TAADAH!');
},
render() {
return (
<BannerAd onBannerClick={this.performMagic} />
);
}
}
but I got the error
Errors prevented startup:
While building for web.browser:
imports/ui/ParentComponent.jsx:5:16: Unexpected token (5:16)
Your application has errors. Waiting for file change.
I think the error is from
performMagic: function() {
alert('TAADAH!');
},
But I do know what the error is.
By the way, can anybody recommends me good debug tools for ReactJS?
Because you're using the ES6 syntax you'll have to bind the function to the instance using the following approach.
constructor(props) {
super(props)
this.performMagic = this.performMagic.bind(this)
}
This will allow you to use the this keyword in the onClick call
import React, { Component } from 'react';
import ChildComponent from './ChildComponent.jsx'
// App component - represents the whole app
export default class ParentComponent extends Component {
constructor(props) {
super(props)
this.performMagic = this.performMagic.bind(this)
}
performMagic() {
alert('TAADAH!');
}
render() {
return (
<BannerAd onBannerClick={this.performMagic} />
);
}
}
Need to write:
performMagic () {
alert('TAADAH!');
},
You need to use new sintax for functions, when write class which is new sintax.
EDIT: You can use "React Developer Tools" chrome extension and gaearon "redux-devtools" for development.
You need to use the new ES6 syntax when making your React Component a class. Use
performMagic() {
alert('TAADAH!');
}
make sure you don't put a comma after the function

Resources