I have similar problem to this thread, using Draft.js wiht React and Typescript.
Using the same code as their docs' example, I get Object is possibly 'null'
error in the focusEditor
function. It persist even when I check for null reference (just like the solution in the SO question I quoted above). Here's the code with added null checks:
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>
);
}
This should be enough to reproduce the error, I have the @types/draft-js
installed as well, no other issues.
The problem is that the type of editor
is implicitly set to React.MutableRefObject<null>
which is an object with a current
property that holds the generic argument passed in. So the signature will be similar to this:
interface MutableRefObject<T> {
current: T | null
}
Since you pass in null
, the generic argument is inferred to also be null
. Therefore, that is the only value that editor.current
should be able to hold.
You should explicitly tell the TypeScript compiler what you expect to have as the generic argument by passing it as useRef<SomeType>()
. You could sidestep the issue by using any
as the generic argument at the price of some type safety but you are better off saying what exactly would that object's type would be. Here is an example:
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();
}
I'm not sure what is the expected type to go there, it might be better to just use HTMLElement
or even something more specific like HTMLTextAreaElement
instead of the Focusable
I created as an example.
At any rate, this can be improved:
React.useRef()
always returns an object and editor
is a constant, thus it cannot be reassigned. This means that it will never be null
. You can remove the first check.
The only thing that could be null
is editor.current
. If you don't want to throw an error, you can simply do a standard null guard which will satisfy the type checking:
if (null !== editor.current) {
editor.current.focus();
}
This can be further shortened using the nullish coalescing operator so you end up with this:
import React from 'react';
const editor = React.useRef<HTMLElement>(null);
function focusEditor() {
editor.current?.focus();
}