Property ‘current’ does not exist on type ‘((instance: HTMLDivElement | null) => void) | RefObject’

There are two kinds of refs in modern react: ref objects, and ref callbacks. Ref objects are what’s created by useRef (or in class components, createRef): it’s an object with a current property. In typescript, these have the type RefObject<T>, where T is whatever value(s) will be on current.

Ref callbacks are another option, which are needed for some advanced cases. You pass a function into the element, and the function will be called back when the instance is created or destroyed. These have the type (instance: T) => void.

A shorthand which combines both the ref object and the ref callback into a single type is Ref<T>, and it looks like that’s what your code expects. Since you haven’t shown that code, I’ll have to make some educated guesses about what it looks like. Suppose you have a component which accepts a ref as a prop (perhaps so it can then hand it off to one of its internal components):

interface ExampleProps {
  buttonRef: Ref<HTMLButtonElement>
}

const Example: FC<ExampleProps> = ({ buttonRef }) => {
  return (
    <div>
      <button ref={buttonRef}>Hello</button>
    <div>
  )
}

Since I’ve defined the prop to be a Ref, it can be passed in either a ref object, or a ref callback. That’s fine in this case, since I’m not doing anything with it except passing it on to the button. But if I try to write some code to interact with it, I can’t assume it to be an object or a function.

If I need to do this, perhaps I could restrict the prop so it only takes ref objects, and then I can assume it will have .current

interface ExampleProps {
  buttonRef: RefObject<HTMLButtonElement>
}

const Example: FC<ExampleProps> = ({ buttonRef }) => {
  useEffect(() => {
    console.log(buttonRef.current);
  });
  return (
    <div>
      <button ref={buttonRef}>Hello</button>
    <div>
  )
}

But maybe I don’t want to restrict the way my component can be used, and yet I still need to be able to interact with the ref. In that case, I’ll probably need to make a callback ref of my own, and then add logic to it to handle both my use of the ref, and the prop’s use of the ref:

interface ExampleProps {
  buttonRef: Ref<HTMLButtonElement>;
}

const Example: FC<ExampleProps> = ({ buttonRef }) => {
  const myRef = useRef<HTMLButtonElement | null>(null);
  useEffect(() => {
    console.log(myRef.current);
  });
  return (
    <div>
      <button
        ref={(element) => {
          myRef.current = element;
          if (typeof buttonRef === "function") {
            buttonRef(element);
          } else {
            buttonRef.current = element;
          }
        }}
      >
        Hello
      </button>
    </div>
  );
};

Leave a Comment