当我将对象显式地包装在`if`中时,为什么TS抱怨该对象可能为空?

时间:2018-10-01 18:40:31

标签: typescript

这是我的代码:

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;
    }
}

消息是:

  

[加载器]中的错误。/src/components/ErrorBoundary.tsx:22:30       TS2531:对象可能为'null'。

enter image description here

但是如果ifthis.state.errorInfo,则null块将不会执行,所以我不确定是什么问题。

为什么会出现此错误以及如何解决?

即使我这样写:

 {this.state.errorInfo !== null ? this.state.errorInfo.componentStack : 'hello'}

 {this.state && this.state.errorInfo ? this.state.errorInfo.componentStack : 'hello'}

我遇到同样的错误。


tsconfig很好:

{
    "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"
    ]
}

3 个答案:

答案 0 :(得分:2)

似乎

state = {error: null, errorInfo: null};

覆盖state的类型。错误信息的推断类型始终为null 您可以通过明确指定类型来纠正它:

state: { error: Error | null, errorInfo: React.ErrorInfo | null } =
{ error: null, errorInfo: null };

在此https://github.com/Microsoft/TypeScript/issues/10570

已报告并讨论了此问题

答案 1 :(得分:0)

状态更新是异步的,在渲染之前,您不应该依赖它进行更新。

您应该阅读有关React component lifecycle

的更多信息

如果您不想使用redux(这也是有争议的-redux很复杂,您只应在需要时使用它,但是状态操作并不容易,因此您仍然应该使用它)

上面说的...只是在您从中读取之前再次执行条件检查(再次异步)

constructor(props) {
  super(props);
  this.state = {init: here};
}
  

您不应在构造函数()中调用setState()。相反,如果您的组件需要使用本地状态,请直接在构造函数中将初始状态分配给this.state。

     

构造函数是唯一应直接分配this.state的地方。在所有其他方法中,您需要改用this.setState()。

答案 2 :(得分:0)

map中使用状态变量时,我仍然看到此问题。

render() {
    if (!this.state.foo) { return <Loading /> }

    [1,2,3].map(n => {
        this.state.foo.property; // Object possibly null
    }

    ...
}

我通过以下方式解决了这个问题:

render() {
    if (!this.state.foo) { return <Loading /> }

    const foo = this.state.foo;

    [1,2,3].map(n => {
        foo.property; // Cool!
    }
    
    ...
}