Reputation: 282805
Here's my code:
import React from 'react';
export default class ErrorBoundary extends React.Component {
state = {error: null, errorInfo: null};
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
this.setState({
error: error,
errorInfo: errorInfo
})
}
render() {
if (this.state.errorInfo) {
return (
<div>
<h2>Something went wrong.</h2>
<pre>
<code>
{String(this.state.error)}
{this.state.errorInfo.componentStack} // <-- error is here
</code>
</pre>
</div>
);
}
return this.props.children;
}
}
Message is:
ERROR in [at-loader] ./src/components/ErrorBoundary.tsx:22:30 TS2531: Object is possibly 'null'.
But the if
block won't execute if this.state.errorInfo
is null
, so I'm not sure what the issue is.
Why am I getting this error and how do I fix it?
Even if I write it like this:
{this.state.errorInfo !== null ? this.state.errorInfo.componentStack : 'hello'}
or
{this.state && this.state.errorInfo ? this.state.errorInfo.componentStack : 'hello'}
I get the same error.
tsconfig for good measure:
{
"compilerOptions": {
"strict": true,
"importHelpers": false,
"inlineSources": true,
"noEmitOnError": true,
"pretty": true,
"module": "ES6",
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": false,
"removeComments": true,
"preserveConstEnums": false,
"sourceMap": true,
"lib": ["es2018","dom"],
"skipLibCheck": true,
"outDir": "dist",
"target": "es2018",
"declaration": true,
"resolveJsonModule": false,
"esModuleInterop": false,
"jsx": "react",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
},
"files": [
"src/index.tsx"
],
"include": [
"src/types/**/*.d.ts"
],
"exclude": [
"node_modules"
]
}
Upvotes: 5
Views: 9530
Reputation: 6781
I was still seeing this issue when using a state variable inside a map
.
render() {
if (!this.state.foo) { return <Loading /> }
[1,2,3].map(n => {
this.state.foo.property; // Object possibly null
}
...
}
I solved this by:
render() {
if (!this.state.foo) { return <Loading /> }
const foo = this.state.foo;
[1,2,3].map(n => {
foo.property; // Cool!
}
...
}
Upvotes: 0
Reputation: 341
state update is asynchronous and u shouldnt rely on it to be updated before rendering.
you should read more about React component lifecycle
if u dont wanna use redux (this is also debatable - redux is complex and u should use it only when u need it, but state manipulation is not easy so u should use it anyway)
with that said... just simply perform a conditional check before u read from it (again async)
constructor(props) {
super(props);
this.state = {init: here};
}
You should not call setState() in the constructor(). Instead, if your component needs to use local state, assign the initial state to this.state directly in the constructor.
Constructor is the only place where you should assign this.state directly. In all other methods, you need to use this.setState() instead.
Upvotes: -2
Reputation: 1520
It seems that
state = {error: null, errorInfo: null};
overrides the state
's type. The inferred type of errorInfo is always null
You can correct it by giving the type explicitly:
state: { error: Error | null, errorInfo: React.ErrorInfo | null } =
{ error: null, errorInfo: null };
This issue is reported and discussed here https://github.com/Microsoft/TypeScript/issues/10570
Upvotes: 8