Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to type a ref parameter with Typescript

I am new to Typescript and I'm currently trying to migrate one of my React.js projects to Typescript. One of the things I stumble on are refs. I have written a hook that is using a ref as a paremeter. Basically it detects if there is a click outside of a div and fire a function that's passed as second parameter. Now I'm wondering how I can type that specific ref. I've tried different solutions such as React.RefObject<any> but don't think using any would be a good idea? What can I use instead? The value is either undefined or a div (Container component is styled component), see code:

Hook

// How to type `ref`?
export function useOnClickOutside(ref: React.RefObject<any>, handler: Function) {
  useEffect(
    () => {
      const listener = (event: MouseEvent | TouchEvent) => {
        // Do nothing if clicking ref's element or descendent elements
        if (!ref.current || ref.current.contains(event.target)) {
          return
        }

        handler(event)
      }

      // MouseEvent
      document.addEventListener('mousedown', listener)
      // TouchEvent
      document.addEventListener('touchstart', listener)

      return () => {
        document.removeEventListener('mousedown', listener)
        document.removeEventListener('touchstart', listener)
      }
    },
    // Add ref and handler to effect dependencies
    [ref, handler]
  )
}


Component

  const containerRef = React.useRef()
  useOnClickOutside(containerRef, () => setIsOpen(false))

  // Some code

  <Container ref={containerRef}>
    // Some code
  </Container

So basically: What should <any> be instead? Thanks in advance.

like image 260
Giesburts Avatar asked Jan 29 '26 21:01

Giesburts


1 Answers

the only part that is related to the type of the ref is this line:

    if (!ref.current || ref.current.contains(event.target)) {

This means the ref is something that has a contains method that takes as input a EventTarget | null object, so the minimum you would need to make it work is this:

interface ValidRefTarget {
  contains(target: EventTarget | null): any;
}

export function useOnClickOutside(ref: React.RefObject<ValidRefTarget>, handler: (event: MouseEvent | TouchEvent)=>void ) {

However since this method is provided by the HTMLElement object you probably want to just use that instead:

export function useOnClickOutside(ref: React.RefObject<HTMLElement>, handler: (event: MouseEvent | TouchEvent)=>void ) {
like image 182
Tadhg McDonald-Jensen Avatar answered Jan 31 '26 09:01

Tadhg McDonald-Jensen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!