Как решить ошибку «Возможно, объект нулевой» в TS? - PullRequest
0 голосов
/ 30 января 2020

У меня похожая проблема с этим потоком , использующим черновик. js с React и Typescript. Используя тот же код, что и в примере с их документами, я получаю ошибку Object is possibly 'null' в функции focusEditor. Это сохраняется даже тогда, когда я проверяю нулевую ссылку (точно так же, как решение в вопросе 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, никаких других проблем.

1 Ответ

1 голос
/ 30 января 2020

Проблема в том, что тип editor неявно установлен на React.MutableRefObject<null>, который является объектом со свойством current, которое содержит переданный аргумент generi c. Таким образом, подпись будет похожа на эту:

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

Поскольку вы передаете null, аргумент generi c также выводится как null. Следовательно, это единственное значение, которое editor.current должно содержать.

Вы должны явно указать компилятору TypeScript, что вы ожидаете получить в качестве аргумента generi c, передав его как useRef<SomeType>(). Вы можете обойти проблему, используя any в качестве аргумента generi c по цене безопасности типов, но вам лучше сказать, каким именно будет тип этого объекта. Вот пример:

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

См. На игровой площадке TypeScript

Я не уверен, какой там ожидаемый тип для go, возможно, лучше просто использовать HTMLElement или даже что-то более конкретное c, например HTMLTextAreaElement вместо Focusable, который я создал в качестве примера.

В любом случае, это можно улучшить:

React.useRef() всегда возвращает объект и editor является константой, поэтому его нельзя переназначить. Это означает, что оно никогда не будет null. Вы можете удалить первую проверку.

Единственное, что может быть null, это editor.current. Если вы не хотите выдавать ошибку, вы можете просто сделать стандартную нулевую защиту, которая будет удовлетворять проверке типа:

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

Это может быть дополнительно сокращено с помощью коалесцирования nulli sh оператор , так что в итоге вы получите:

import React from 'react';

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

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

См. на TypeScript Playground

...