Skip to main content

How do you type useRef()?

1. What useRef does

useRef creates a ref object ({ current: ... }), which React keeps across renders.

The type signature:

javascript
function useRef<T>(initialValue: T): MutableRefObject<T>;

2. Basic typing

javascript
const countRef = useRef<number>(0); countRef.current++; // current is a number

TypeScript knows that countRef.current is number. If you pass an initial value, TS infers the type automatically:

javascript
const flagRef = useRef(false); // inferred: MutableRefObject<boolean>

3. If it starts out as null (DOM or lazy references)

When a ref starts out as null, you must specify the type explicitly:

javascript
// A reference to a DOM element const inputRef = useRef<HTMLInputElement | null>(null);

Here current can be null before mounting. When using it:

javascript
inputRef.current?.focus();

Safe: ?. guards against null.


4. Passing a ref into an element

javascript
export function Form() { const inputRef = useRef<HTMLInputElement | null>(null); return <input ref={inputRef} type="text" />; }

TypeScript already knows that inputRef.current is HTMLInputElement | null.

For different elements:

  • HTMLDivElement
  • HTMLButtonElement
  • HTMLFormElement
  • HTMLTextAreaElement
  • HTMLAnchorElement and so on.

5. When you only need to store a value (not DOM)

javascript
const intervalId = useRef<number | null>(null); useEffect(() => { intervalId.current = window.setInterval(() => console.log('tick'), 1000); return () => clearInterval(intervalId.current!); }, []);

Useful for storing mutable variables without a re-render.


6. An example with forwardRef

javascript
type InputProps = React.ComponentProps<"input">; const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => { return <input ref={ref} {...props} />; }); // Usage const inputRef = useRef<HTMLInputElement>(null); <Input ref={inputRef} />;

forwardRef takes two type parameters:

javascript
React.forwardRef<ElementType, PropsType>()

7. When you need useRef<T | null>(null) vs useRef<T>(...)

ScenarioType
A DOM element (mounts later)useRef<T | null>(null)
A simple variable (number, object, etc.)useRef<T>(value)
Lazy initializationuseRef<T | null>(null)

8. A "readonly ref" (an immutable reference)

If the reference will not be changed manually, you can use React.RefObject<T>:

javascript
const divRef: React.RefObject<HTMLDivElement> = useRef(null);

RefObject = { readonly current: T | null }

Used when you just pass the ref along without modifying it.


9. An example: click outside an element

javascript
function Dropdown() { const menuRef = useRef<HTMLDivElement | null>(null); useEffect(() => { function handleClick(e: MouseEvent) { if (!menuRef.current?.contains(e.target as Node)) { console.log("Clicked outside"); } } document.addEventListener("click", handleClick); return () => document.removeEventListener("click", handleClick); }, []); return <div ref={menuRef}>Menu</div>; }

menuRef.current is typed correctly. contains() is called safely.


Summary

ScenarioTyping
A simple ref variableuseRef<number>(0)
A DOM refuseRef<HTMLDivElement | null>(null)
A ref on <input>useRef<HTMLInputElement | null>(null)
A ref for a timer / iduseRef<number | null>(null)
Read-onlyReact.RefObject<T>
With forwardRefReact.forwardRef<T, Props>()

In short:

  • Always add | null if the ref is for the DOM.
  • Do not write any. Use the exact element type (HTMLDivElement, HTMLInputElement, etc.).
  • To store "mutable" data without a re-render, use useRef<T>().
  • For references between components, use forwardRef() with a generic.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.