Last updated: Jan 15, 2023
Reading timeยท3 min
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 that 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 its 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
.
any
typeIf 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" />
.
You can learn more about using TypeScript with React by checking out the following tutorials: