头图

The text starts here~

type guard

Use type guards to resolve the useRef hook "Object is possibly null" error in React. For example, if (inputRef.current) {} . Once null is excluded from the type of ref , we are able to access the properties on ref .

useref-object-is-possibly-null.webp

Below is an example of how an error can occur.

 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 problem in the snippet is that TypeScript can't ensure that we assign an element or a value to a ref, so its current property could be null .

To fix this error, we have to use a type guard to exclude null from its type before accessing properties on the ref type.

 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 use a simple if statement as a type guard to ensure that the ref current property on ---9e858ab876b6c785b9ab47cecb83527e--- does not store null . When the program enters the if block, TypeScript will know that the ---8521b27e464ef25d7ca3fea5aa906bdaa--- property on the current ref will not store the null ---property.

Make sure to use generics on the useRef hook, correct type declaration ref current .

Note that we passed a generic to ref the value type of ---f217f0c193605fdc93ce6ed38793b0d2--- as HTMLInputElement .

一些常用的类型有: HTMLInputElement , HTMLButtonElement , HTMLAnchorElement , HTMLImageElement , HTMLTextAreaElement , HTMLSelectElement Wait.

If you store a different value in ref , make sure to pass a specific type to the generic type of the useRef hook, e.g. const ref = useRef<{name: string}>(null); .

If the ref current attribute on ---79b39c20e98a37ba169075c44bbc47db--- stores null , we can also use the optional chain ?. to short-circuit the operation.

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

If the reference is null ( null or undefined ), the optional chaining ?. operator will short-circuit without throwing an error.换句话说, ref上的current null ,操作符会短路运算从而返回undefined 。 instead of trying to call the undefined focus method on ---a121fed99a9f6eb64ab4758b8e226146---, resulting in a runtime error.

non-null assertion

Another solution is to use the non-null assert ! 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>
  );
}

In TypeScript, the exclamation mark is called the non-null assertion operator. Used to remove null and undefined from a type without any explicit type checking.

When we use a non-null assertion, we are basically telling TS that the ref current attribute on the object will not be stored null or undefined .

Note that this approach is not type-safe, as TypeScript does not perform any checks to ensure the property is not null.

Summarize

The "Object is possibly null" error is caused because useRef() the hook can pass an initial value as a parameter, and we pass null as the initial value. The hook returns a mutable ref object whose .current property is initialized to the passed parameter.

When passing the ref prop to an element, such as <input ref={myRef} /> , React will set the ref object's .current property to the corresponding DOM node, but TypeScript can't tell if our will set ref as a DOM element, or set its value later in our code.


chuck
303 声望41 粉丝