The error "React - Property 'X' does not exist on type 'Readonly<{}>'. " occurs when we access a prop or state of a React class component which hasn't been given a type.

error

Problem

Let's see an example of how the error occurred:

import React from "react";

class App extends React.Component {
  constructor(props: any) {
    super(props);
    this.state = { name: "" };
  }

  handleChange = (event: any) => {
    this.setState({ name: event.target.value });
  };

  render() {
    return (
      <div>
        <form>
          <input onChange={this.handleChange} type="text" value={this.state.name} />  //πŸ‘ˆ Accessing name will result in error since it is not typed
          <button type="submit">Submit</button>
        </form>
      </div>
    );
  }
}

export default App;

Since we have not typed the state property 'name', it will result in a "property does not exist on type 'Readonly<{}>'." error.

Solutions

We can overcome this by using a generic 'React.Component' class as 'React.Component<PropsObject, StateObject>'. See the following code with the fix:

import React from "react";

class App extends React.Component<{}, { name: string }> {  //πŸ‘ˆ typed state variable
  constructor(props: any) {
    super(props);
    this.state = { name: "" };
  }

  handleChange = (event: any) => {
    this.setState({ name: event.target.value });
  };

  render() {
    return (
      <div>
        <form>
          <input onChange={this.handleChange} type="text" value={this.state.name} />
          <button type="submit">Submit</button>
        </form>
      </div>
    );
  }
}

export default App;

Here, we have typed the property 'name' as a string and hence resolved the issue.

However, you might have noticed another empty object before we defined the type for the state properties.

class App extends React.Component<{}, { name: string }> 

This is because the first object is for typing the props that are being passed to the class component.

Typing both state and props

See the following example:

import React from "react";

class App extends React.Component<{ title: string }, { name: string }> {
  constructor(props: any) {
    super(props);

    this.state = { name: "" };
  }

  handleChange = (event: any) => {
    this.setState({ name: event.target.value });
  };

  render() {
    return (
      <div>
        <form>
          <input onChange={this.handleChange} type="text" value={this.state.name} />
          <button type="submit">Submit</button>
        </form>

        <h1>{this.props.title}</h1>
      </div>
    );
  }
}

export default App;

Here, we are typing both the prop that is being passed to the App component and the states defined inside. This enables us to access any value without getting a type checking error in TypeScript.

Conclusion

The error "Property 'X' does not exist on type 'Readonly<{}>'." occurs when we access a prop or state property that we have not explicitly given a type inside the React class component.