Jordan
Jordan

Reputation: 950

useRef Typescript error: Property 'current' does not exist on type 'HTMLElement'

I'm making a Datepicker with React and Typescript, and I can't seem to get over the errors with useRef and the ref's .current property. I'm trying to get the div I'm assigning the ref to to close when the document is clicked outside of it.

I just can't quite seem to figure out what I'm doing wrong. Here is my code:

function Datepicker({label, placeholder}: DatepickerProps){
  const [open, setOpen] = React.useState(false)
  const [day, setDay] = React.useState(0)
  const [month, setMonth] = React.useState(new Date().getMonth())
  const [year, setYear] = React.useState(new Date().getFullYear())
  const picker = React.useRef(null) as HTMLElement | null

  React.useEffect(() => {
    document.addEventListener("mousedown", toggle)
    return () => {
      document.removeEventListener("mousedown", toggle)
    };
  }, []);

  const toggle = (e: MouseEvent) => {
    if (picker && picker.current){
      if (picker.current.contains(e.target) === false){
        setOpen(false)
      }
    }
  }

  //...

  return(
    
    //...

    <div 
      ref={picker}
      className={"datepicker-picker" + (open ? " open" : "")}
    >

      //...

  )
}


React.useRef(null) as HTMLElement | null is giving me the following problem:

Conversion of type 'MutableRefObject<null>' to type 'HTMLElement' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'MutableRefObject<null>' is missing the following properties from type 'HTMLElement': accessKey, accessKeyLabel, autocapitalize, dir, and 234 more.ts(2352)

.current is giving me the following:

Property 'current' does not exist on type 'HTMLElement'.

and when I try to apply the ref to a div element, its says the following:

Type 'HTMLElement | null' is not assignable to type 'string | ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null | undefined'.
  Type 'HTMLElement' is not assignable to type 'string | ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null | undefined'.
    Type 'HTMLElement' is not assignable to type 'string'.ts(2322)
index.d.ts(143, 9): The expected type comes from property 'ref' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'

I'm using VSCode as my IDE, if that helps at all.

Upvotes: 17

Views: 31784

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370729

useRef does not return the value in the ref - asserting the type of the return value as HTMLElement | null is inaccurate. Use a generic type argument instead:

const picker = React.useRef<HTMLElement>(null);

You'll also need to change toggle so that the type narrowing occurs as desired:

const toggle = (e: MouseEvent) => {
  const { current } = picker;
  if (current && !current.contains(e.target)) {
    setOpen(false);
  }
}

Upvotes: 22

Related Questions