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 ponent is styled ponent), 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.
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 ponent is styled ponent), 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.
- You can use <HTMLDivElement> as mentioned in medium./@martin_hotell/… – Sujit Kumar Singh Commented Sep 30, 2020 at 17:01
- Is it optional or you will get always? – Suleman Ahmad Commented Sep 30, 2020 at 17:07
-
ref.current.contains(event.target)
this means your ref should be typed to have acontains
method that takes aHTMLElement
as input, I.E. the ref is to aHTMLElement
. – Tadhg McDonald-Jensen Commented Sep 30, 2020 at 17:35
1 Answer
Reset to default 9the 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 ) {