Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid redeclaring props type in React constructor using Typescript

Let's say I have a class like this:

class PeopleByTag extends React.Component<RouteComponentProps<{ tag: string }>

I need to do something in my constructor, in this example fetch data, but to do that I need to declare a props parameter, but if I don't specify the type it will become any:

constructor(props) {
    super(props); // props is any
    this.loadData();
}

On the other hand, if I redeclare the type the code gets very ugly:

constructor(props: Readonly<{
    children?: React.ReactNode;
}> & Readonly<RouteComponentProps<{
    tag: string;
}, StaticContext, any>>) {
    super(props);
    this.loadData();
}

Is there a way to automatically infer the props type from the class extension while also being able to write a constructor?

I also don't want to use the deprecated lifecycle hooks (i.e. ComponentWillMount).

like image 458
Ricardo Smania Avatar asked Oct 14 '18 12:10

Ricardo Smania


People also ask

Why do we pass props in constructor in React?

Explanation: If we want to use this in the constructor, we need to pass it to super. If we want to use this. props inside the constructor we need to pass it with the super() function. Otherwise, we don't want to pass props to super() because we see this.

What is props type React TypeScript?

PropTypes provide built-in typechecking capabilities when writing a React app. Checking the type of prop in a React component in a large application helps catch bugs at run-time. Typically in a React app, you will need to install the package yarn add prop-types .

What is props in constructor React?

props. In React, the constructor is called during component creation and before mounting. If you want to implement the constructor for a React component, call the super(props) method before any other statement. Otherwise, this. props will be undefined in the constructor and create bugs.

Does not exist on type readonly state?

js error "Property does not exist on type 'Readonly<{}>'" occurs when we try to access the props or state of a class component which we haven't typed. To solve the error, use the generic on the React. Component class to type the props or state objects of the class. Here is an example of how the error occurs.

Why should I use typescript with react?

One advantage of using React with TypeScript is that you can easily type the props of your (function) components. You don't have to use React's PropTypes because TypeScript already has its own typing system. In the following, I will show you how to define custom props for a component in connection with already existing props like children.

Do I have to use React's proptypes?

You don't have to use React's PropTypes because TypeScript already has its own typing system. In the following, I will show you how to define custom props for a component in connection with already existing props like children. As you can see, our PostPreview component has a heading property.

How do I add default props to a stateful React component?

Adding default props to a stateful component in React with TypeScript has been a pain. TypeScript 3 is making this process as simple as: Add a static defaultProps object at the top of your component and you're done Here's a simple example with a component that has a prop to change the color.

How do you define props in typescript?

Whether you're coming in fresh to using Typescript with React or are a grizzled veteran looking to add more functional components to your codebase by introducing hooks, it's important to know the different ways to define props. One of the ways you can define props is simply by defining them in the parameter list of a function as demonstrated above.


1 Answers

Usually constructor itself shouldn't get 'very ugly', just because types can be defined separately as type or interface in case parameter types are verbose.

Constructor props parameter cannot be inferred because React.Component<RouteComponentProps<{ tag: string }>> generic parameter refers to parent class, React.Component, not current class.

As it can be seen in type definitions, this infers proper type for parent constructor, i.e. super.

So this

constructor(props) {
    super(props);
}

is valid. this.props is still properly typed.

In case noImplicitAny compiler option is used, it is:

constructor(props: any) {
    super(props);
}

The use of props typed as any in constructor may result in type mistakes:

constructor(props: any) {
    super(props);

    props.tag; // ok
    props.nonexistentProp; // ok
}

While this.props is type-safe.

A class can be typed with as generic to maintain proper props type in constructor, but this can be considered overkill:

export class PeopleByTag<P extends { tag: string }> extends React.Component<P> {
  constructor(props: Readonly<P>) {
    super(props); // props is any

    props.tag; // ok
    props.nonexistentProp; // not ok
    props.children; // not ok, but we rarely ever need children in constructor
  }
}

It may be beneficial to prevent the use of props in constructor by providing incompatible type for it:

constructor(props: never) {
    super(props);

    props.tag; // not ok
}

If props argument was passed to super, this.props and props are interchangeable in JavaScript. They aren't interchangeable in TypeScript. this.props may be accessed in constructor for properly typed props.

like image 174
Estus Flask Avatar answered Oct 25 '22 15:10

Estus Flask