Last updated: Feb 29, 2024
Reading timeยท3 min
Use a type guard to solve the "Object is possibly null" error with the useRef
hook in React, e.g. if (inputRef.current) {}
.
Once null
is excluded from the ref's type, we can access properties on the
ref that correspond to its type.
Here is an example of how the error occurs.
import {useEffect, useRef} from 'react'; export default function App() { const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { // โ๏ธ Object is possibly 'null'.ts(2531) inputRef.current.focus(); }, []); return ( <div> <input ref={inputRef} type="text" id="message" /> <button>Click</button> </div> ); }
The issue is that TypeScript has no guarantee that we'll assign the ref to an
element or assign a value to it, so its current
property could possibly be
null
.
To solve the error, use a type guard to exclude null
from the ref's type
before accessing properties on it.
import {useEffect, useRef} from 'react'; export default function App() { const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { // ๐๏ธ ref could be null here if (inputRef.current != null) { // ๐๏ธ TypeScript knows that ref is not null here inputRef.current.focus(); } }, []); return ( <div> <input ref={inputRef} type="text" id="message" /> <button>Click</button> </div> ); }
We used a simple if statement as a
type guard
to make sure the current
property on the ref does not store a null
value.
TypeScript knows that the current
property on the ref
object does not store
a null
value once we enter the if
block.
useRef
hook to type the current
property of your ref correctlyNote that we passed a generic to type the value of the
ref to an HTMLInputElement
.
HTML***Element
. Once you start typing HTML..
, your IDE should be able to help you with autocomplete.Some commonly used types are: HTMLInputElement
, HTMLButtonElement
,
HTMLAnchorElement
, HTMLImageElement
, HTMLTextAreaElement
,
HTMLDivElement
etc.
If you store a different value in your ref, make sure to pass the specific type
to the generic of the useRef()
hook, e.g.
const ref = useRef<{name: string}>(null);
.
We could have also used the
optional chaining (?.)
operator to short-circuit if the current
property on the ref stores a null
value.
import {useEffect, useRef} from 'react'; export default function App() { const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { // ๐๏ธ optional chaining (?.) inputRef.current?.focus(); }, []); return ( <div> <input ref={inputRef} type="text" id="message" /> {/* Cannot find name 'button'.ts(2304) */} <button>Click</button> </div> ); }
The optional chaining (?.) operator short-circuits instead of throwing an error
if the reference is nullish (null
or undefined
).
current
property on the ref stores a null
value, the operator would short-circuit returning undefined
instead of try to call the focus()
method on an undefined
value and cause a runtime error.An alternative solution to the error with refs in React is to use the non-null (!) assertion operator.
import {useEffect, useRef} from 'react'; export default function App() { const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { // ๐๏ธ using non-null (!) assertion inputRef.current!.focus(); }, []); return ( <div> <input ref={inputRef} type="text" id="message" /> {/* Cannot find name 'button'.ts(2304) */} <button>Click</button> </div> ); }
null
and undefined
from a type without doing any explicit type-checking.When we use it, we basically tell TypeScript that the current
property on the
ref object does not store a null
or an undefined
value.
Note that this approach is not type-safe as TypeScript doesn't perform any checks to make sure the property is not nullish.
The "Object is possibly null" error is caused because the useRef()
hook can be
passed an initial value as an argument and we're passing it null
as an initial
value.
The hook returns a mutable ref object whose .current
property is initialized
to the passed argument.
When we pass a ref prop to an element, e.g. <input ref={myRef} />
, React sets
the .current
property of the ref object to the corresponding DOM node, but
TypeScript can't be sure that we're going to set the ref to a DOM element or set
its value later in our code.