How to Fix "Cannot assign to current because it is a read-only property" useRef() TypeScript Error?

Why Does This Happen?

This error occurs when the current property of the reference is deemed to be immutable. This is the case when:

  1. A specific type is provided to useRef() (e.g., useRef<number>), and;
  2. The initial value of useRef is set to null (e.g., useRef(null)).

For instance, this is evident in the following code, where the current property of the reference object is set as readonly, triggering a TypeScript error upon reassignment:

// ...
const ref = useRef<number>(null); // immutable

useEffect(() => {
  // Error: Cannot assign to current because it is a read-only property.
  ref.current = 1;
}, []);

// ...

In this case, internally, the reference "ref" is assigned the "RefObject" type, which is defined as:

interface RefObject<T> {
  readonly current: T | null;
}

This makes the current property immutable, as it's marked as readonly.

How to Fix the Issue?

Depending on your use case, you can resolve this problem by specifying the type for useRef() in the following ways:

  1. Initializing to null

    When initializing the current property of the reference object to null, you can keep it mutable by appending " | null" to the generic argument:

    // ...
    const ref = useRef<number | null>(null); // mutable
    
    useEffect(() => {
      ref.current = 1;
    }, []);
    
    // ...
    

    Internally, this sets the type as "MutableRefObject", which is defined as:

    interface MutableRefObject<T> {
      current: T;
    }
    
  2. Initializing to a Non-Null Value

    When you specify the initial value of useRef() as a non-null value, it is set as "MutableRefObject" as well, allowing the current property of the reference to be mutated:

    // ...
    const ref = useRef<number>(2); // mutable
    
    useEffect(() => {
      ref.current = 1;
    }, []);
    
    // ...
    
  3. Initializing to undefined

    When you initialize useRef() to an undefined value, it is set as "MutableRefObject<T | undefined>" internally, allowing the current property of the reference to be mutated:

    // ...
    const ref = useRef<number>(); // mutable
    
    useEffect(() => {
      ref.current = 1;
    }, []);
    
    // ...
    

Specifying the type to the React useRef() hook in any of these ways will allow you to re-assign the current property of the reference object without TypeScript complaining.


This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.