HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptreactCritical

What typescript type do I use with useRef() hook when setting current manually?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
typescriptmanuallywithusesettingcurrenttypewhenwhathook

Problem

How can I use a React ref as a mutable instance, with Typescript? The current property appears to be typed as read-only.

I am using React + Typescript to develop a library that interacts with input fields that are NOT rendered by React. I want to capture a reference to the HTML element and then bind React events to it.

const inputRef = useRef();
  const { elementId, handler } = props;

  // Bind change handler on mount/ unmount
  useEffect(() => {
    inputRef.current = document.getElementById(elementId);
    if (inputRef.current === null) {
      throw new Exception(`Input with ID attribute ${elementId} not found`);
    }
    handler(inputRef.current.value);

    const callback = debounce((e) => {
      eventHandler(e, handler);
    }, 200);

    inputRef.current.addEventListener('keypress', callback, true);

    return () => {
      inputRef.current.removeEventListener('keypress', callback, true);
    };
  });


It generates compiler errors: semantic error TS2540: Cannot assign to 'current' because it is a read-only property.

I also tried const inputRef = useRef(); This lead to this compiler error:

Type 'HTMLElement | null' is not assignable to type '{ current: HTMLInputElement; } | undefined'.

  Type 'null' is not assignable to type '{ current: HTMLInputElement; } | undefined'.

Solution

Yeah, this is a quirk of how the typings are written:

function useRef(initialValue: T): MutableRefObject;
function useRef(initialValue: T | null): RefObject;


  • If the type of the initialValue and type parameter T match, you'll hit the first override and get a MutableRefObject.



  • If the type of the initialValue includes null and type parameter T doesn't, you'll hit the second override and get an immutable RefObject.



You're hitting the second case when you're doing this:

useRef(null)


T is specified as HTMLInputElement and the type of null is inferred as HTMLInputElement | null.

You can hit the first case by doing this:

useRef(null)


T is specified as HTMLInputElement | null and the type of null is inferred as HTMLInputElement | null.

Code Snippets

function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T | null): RefObject<T>;
useRef<HTMLInputElement>(null)
useRef<HTMLInputElement | null>(null)

Context

Stack Overflow Q#58017215, score: 420

Revisions (0)

No revisions yet.