Borislav Hadzhiev
Tue Mar 22 2022·3 min read
Photo by Jimmy Conover
The React.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.
import React from 'react'; class App extends React.Component { constructor(props: any) { super(props); this.state = {value: ''}; // 👈️ uses state but we haven't typed it } handleChange = (event: any) => { this.setState({value: event.target.value}); }; render() { return ( <div> <form> {/* ⛔️ Error: Property 'value' does not exist on type 'Readonly<{}>'.ts(2339) */} <input onChange={this.handleChange} type="text" value={this.state.value} /> <button type="submit">Submit</button> </form> </div> ); } } export default App;
Notice that our class component has a value
property in it's state object.
The same is the case for the props
object - trying to access a property on the
props object would cause an error if we don't explicitly type it.
To solve the error, use the generic of the React.Component
class as
React.Component<PropsObject, StateObject>
.
import React from 'react'; // 👇️ we set the props to empty object, and set the state to {value: string} class App extends React.Component<{}, {value: string}> { constructor(props: any) { super(props); this.state = {value: ''}; } handleChange = (event: any) => { this.setState({value: event.target.value}); }; render() { return ( <div> <form> <input onChange={this.handleChange} type="text" // ✅ Everything works now value={this.state.value} /> <button type="submit">Submit</button> </form> </div> ); } } export default App;
We typed the value
property on the state
object in the class, so we are now
able to access it as this.state.value
.
If you don't know how to type the props or state objects and want to disable
type checking, use the any
type.
import React from 'react'; // 👇️ type checking disabled for props and state class App extends React.Component<any, any> { constructor(props: any) { super(props); this.state = {value: ''}; } handleChange = (event: any) => { this.setState({value: event.target.value}); }; render() { return ( <div> <form> <input onChange={this.handleChange} type="text" value={this.state.value} /> <button type="submit">Submit</button> </form> </div> ); } } export default App;
We used the any
type when typing the props
and state
objects, which
effectively turns off type checking.
this.props
and this.state
objects without getting a type checking error.Here is an example of a class that also explicitly types the props object.
import React from 'react'; // 👇️ type props as {name: string}, and state as {value: string} class App extends React.Component<{name: string}, {value: string}> { constructor(props: any) { super(props); this.state = {value: ''}; } handleChange = (event: any) => { this.setState({value: event.target.value}); }; render() { return ( <div> <form> <input onChange={this.handleChange} type="text" value={this.state.value} /> <button type="submit">Submit</button> </form> <h1>{this.props.name}</h1> </div> ); } } export default App;
We explicitly typed the props object of the App
component to have a name
property of type string
. Now when you use the component, you would have to
provide the name prop, e.g. <App name="James Doe" />
.
To solve the React.js error "Property does not exist on type 'Readonly<{}>'", make sure to explicitly type the props or state object of the class, adding any of the properties you intend to access on the props or state objects.