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.
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.