如何解决 TS 中的 'Object possibly null' 错误?

How do I solve 'Object possibly null' error in TS?

我有与此 thread 类似的问题,使用 Draft.js 和 React 和 Typescript。 使用与他们的文档示例相同的代码,我在 focusEditor 函数中得到 Object is possibly 'null' 错误。即使在我检查空引用时它仍然存在(就像我上面引用的 SO 问题中的解决方案一样)。这是添加了空检查的代码:

import React from 'react';
import { Editor, EditorState } from 'draft-js';

export default () => {
  const [editorState, setEditorState] = React.useState(
    EditorState.createEmpty()
  );

  const editor = React.useRef(null);

  function focusEditor() {
    if (null === editor) {
      throw Error('editor is null') 
    }
    if (null === editor.current) {
      throw Error('editor.current is null') 
    }
    editor.current.focus(); // Error: Object is possibly 'null'
  }

  React.useEffect(() => {
    focusEditor()
  }, []);

  return (
    <div onClick={focusEditor}>
      <Editor
        ref={editor}
        editorState={editorState}
        onChange={editorState => setEditorState(editorState)}
      />
    </div>
  );
}

这应该足以重现错误,我也安装了 @types/draft-js,没有其他问题。

问题是 editor 的类型被隐式设置为 React.MutableRefObject<null>,这是一个带有 current 属性 的对象,其中包含传入的通用参数。所以签名将类似于:

interface MutableRefObject<T> {
  current: T | null
}

由于您传入 null,通用参数也被推断为 null。因此,这是 editor.current 应该能够保持的唯一值。

您应该通过将其作为 useRef<SomeType>() 传递来明确告诉 TypeScript 编译器您希望将什么作为通用参数。您可以以某种类型安全为代价,通过使用 any 作为通用参数来回避这个问题,但您最好说出该对象的类型到底是什么。这是一个例子:

import React from 'react';

interface Focusable {
  focus: () => void
}

const editor = React.useRef<Focusable>(null);

function focusEditor() {
  if (null === editor) {
    throw Error('editor is null') 
  }
  if (null === editor.current) {
    throw Error('editor.current is null') 
  }
  editor.current.focus(); 
}

See on TypeScript Playground

我不确定去那里的预期类型是什么,最好只使用 HTMLElement 或者更具体的东西,比如 HTMLTextAreaElement 而不是 Focusable我创建了一个例子。

无论如何,这可以改进:

React.useRef()总是returns一个对象editor是一个常量,因此它不能被重新分配。这意味着它永远不会是 null。您可以删除第一个支票。

唯一可能 null 的是 editor.current。如果你不想抛出错误,你可以简单地做一个标准的 null guard 来满足类型检查:

if (null !== editor.current) {
  editor.current.focus();
}

这可以使用 nullish coalescing operator 进一步缩短,所以你最终得到这个:

import React from 'react';

const editor = React.useRef<HTMLElement>(null);

function focusEditor() {
  editor.current?.focus();
}

See on TypeScript Playground