← Back to TypeScript Course | Chapter 14: TypeScript with React | Lesson 6 of 8

Typing useRef

useRef can store a reference to a DOM element or a mutable value that persists between renders. TypeScript generics describe the type of value held by the ref.
Syntax
typescript
const ref = useRef<HTMLElementType>(null);

Typing DOM Element Refs

Typing a ref meant for a DOM element — useRef<HTMLInputElement>(null) — gives .current the type HTMLInputElement | null, matching that the ref genuinely starts out unattached before the component first renders.

Example: Typing DOM Element Refs

typescript
import React, { useRef } from "react";

function TextInput(): React.JSX.Element {
	const inputRef = useRef<HTMLInputElement>(null);
	return <input ref={inputRef} />;
}

export default TextInput;

Typing Mutable Values

A ref holding a mutable value that isn't a DOM node — like a timer ID — is typed with useRef<number>(initialValue), and unlike state, changing .current never triggers a re-render.

Example: Typing Mutable Values

typescript
import React, { useRef } from "react";

function Timer(): React.JSX.Element {
	const timerId = useRef<number>(0);
	timerId.current = 42;
	return <p>Timer id stored: {timerId.current}</p>;
}

export default Timer;

Refs with Nullable Values

Because a DOM ref's .current starts as null, every place you use it needs a null check first, which TypeScript enforces automatically once the ref is typed correctly instead of loosely as any.

Example: Refs with Nullable Values

typescript
import React, { useRef, useEffect } from "react";

function Focusable(): React.JSX.Element {
	const ref = useRef<HTMLInputElement>(null);
	useEffect(() => {
		if (ref.current) ref.current.focus();
	}, []);
	return <input ref={ref} />;
}

export default Focusable;

useRef with useEffect

Combining useRef with useEffect is the standard pattern for reading a DOM node's real dimensions or focusing it after mount, since the ref is guaranteed to be attached by the time the effect runs.

Example: useRef with useEffect

typescript
import React, { useRef, useEffect } from "react";

function Measured(): React.JSX.Element {
	const ref = useRef<HTMLDivElement>(null);
	useEffect(() => {
		if (ref.current) console.log(ref.current.clientWidth);
	}, []);
	return <div ref={ref}>content</div>;
}

export default Measured;

Typing Custom Ref Values

Typing a custom ref value forwarded through forwardRef requires specifying the ref's type as the first generic argument, letting a parent component safely call methods exposed by a child through useImperativeHandle.

Example: Typing Custom Ref Values

typescript
import React, { forwardRef, useImperativeHandle } from "react";

interface InputHandle {
	focus: () => void;
}

const CustomInput = forwardRef<InputHandle>((props, ref) => {
	useImperativeHandle(ref, () => ({ focus: () => console.log("focused") }));
	return <input />;
});

export default CustomInput;
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Calling useRef<HTMLInputElement>() without null, so .current is typed as possibly undefined and cannot be passed to ref.
  2. Using inputRef.current.focus() without a null check, which errors because .current may be null.
  3. Expecting a change to ref.current to re-render the component, when refs do not trigger renders.
🔒

Chapter Quiz — Complete all 8 topics to unlock

0/8 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.