why is typescript complaining when trying to use ref in react?

Viewed 2470

I am using ref to animate elements on scroll.

  const foo = () => {
    if (!ref.current) return;
    const rect = ref.current.getBoundingClientRect();
    setAnimClass(
      rect.top >= 0 && rect.bottom <= window.innerHeight ? styles.animClass : ""
    );
  };

this code worked well in next.js app. but when I am using this in create-react-app type-script template, it is complaining that Object is possibly 'null'.

From if (!ref.current) return; it is clear that program will be returned if ref.current does not exist. But still TypeScript give error on the next line ref.current.getBoundingClientRect(), pointing at the ref.

How to solve this issue without removing the null checking from typescript config?

complete file - https://github.com/mayank1513/react-contact-app/blob/master/src/components/ContactListItem.tsx

This is the complete project repo - https://github.com/mayank1513/react-contact-app

As of now I have bypassed the issue using "strict": false in tsconfig. But need to do it in strict mode.

Similar issue in this file as well. And this is not resolved even by setting "strict": false in tsconfig. For now I am just relying on document.getElementById() -- around line 65

3 Answers

Try this:

const ref = useRef() as RefObject<HTMLDivElement>;

const foo = () => {
    if (!ref.current) return;
    const rect = ref.current.getBoundingClientRect();
    setAnimClass(
      rect.top >= 0 && rect.bottom <= window.innerHeight ? styles.animClass : ""
    );
  };

This is simple just add type HTMLDivElement to useRef, and the error didn't show up anymore:

const ref = useRef<HTMLDivElement>(null);

Bonus: you should always remove the listener inside useEffect:

useEffect(() => {
  foo();
  window.addEventListener("scroll", foo);
  window.addEventListener("resize", foo);
  return () => {
    window.removeEventListener("scroll", foo);
    window.removeEventListener("resize", foo);
  }
}, []);

you can cast ref to any as you get it from react.
const ref = useRef(null) as any;

Edit: I wanted to come back and give a more strongly typed solution, but Sakshi's answer does just that. This is the lazy fix, so follow their solution.

Related