Problem
The type for useRef
looks like this:
/**
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
* (`initialValue`). The returned object will persist for the full lifetime of the component.
*
* Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
* value around similar to how you’d use instance fields in classes.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
function useRef<T>(initialValue: T): MutableRefObject<T>;
// convenience overload for refs given as a ref prop as they typically start with a null value
/**
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
* (`initialValue`). The returned object will persist for the full lifetime of the component.
*
* Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
* value around similar to how you’d use instance fields in classes.
*
* Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type
* of the generic argument.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
function useRef<T>(initialValue: T|null): RefObject<T>;
// convenience overload for potentially undefined initialValue / call with 0 arguments
// has a default to stop it from defaulting to {} instead
/**
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
* (`initialValue`). The returned object will persist for the full lifetime of the component.
*
* Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
* value around similar to how you’d use instance fields in classes.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
function useRef<T = undefined>(): MutableRefObject<T | undefined>;
– reference
It either returns a RefObject
or a MutableRefObject
. They essentially have the same shape and look like this:
interface RefObject<T> {
readonly current: T | null;
}
– reference
interface MutableRefObject<T> {
current: T;
}
– reference
From the above you can see the type of current
takes on the type of the argument useRef
is called with. You called useRef
with null
, therefore T
has a type of null
, therefore current
has a type of null
. The contains
method cannot be called on null
hence the TypeScript error.
Solution
useRef
accepts a type parameter (see generics) which allows you to give a type to T
yourself. You might do something like this (replace HTMLElement
with a type more specific to your case):
import { useRef } from "react";
const myElement = useRef<HTMLElement>(null);
const handleClickOutside = (e: MouseEvent) => {
if (!myElement.current?.contains(e.target)) {
// do something
}
};
TypeScript Playground