reactjs - React onclick Argument av typen 'EventTarget' kan ikke tildeles til parameter av typen 'Node'


Jeg importerer MouseEvent fra react

import { MouseEvent } from 'react';

Bruk MouseEvent i følgende

  const closeSelectBox = (e: MouseEvent): void => {
    if (!searchOptionWrapRef.current?.contains(e.target)) {
      setOpenSelectBox(false)
    }
  };

Jeg lytter til min closeSelectBox

  useEffect(() => {
    document.addEventListener("click", closeSelectBox);
    return () => {
      document.removeEventListener("click", closeSelectBox);
    };
  }, [])

searchOptionWrapRef er en div

const searchOptionWrapRef = useRef<HTMLDivElement>(null);

<div ref={searchOptionWrapRef}/>

Men jeg får følgende feil

Argument of type 'EventTarget' is not assignable to parameter of type 'Node'.
  Type 'EventTarget' is missing the following properties from type 'Node': baseURI, childNodes, firstChild, isConnected, and 43 more.

Hvordan løser jeg denne typefeilen uten å bruke any i stedet for MouseEvent?

Svar #1

Hendelsesgrensesnittene som eksporteres av React er for React-hendelsesbehandlerprops, ikke addEventListener-behandlere. For disse, ikke importer MouseEvent fra React, så får du i stedet DOM globalt grensesnitt for det, som fungerer med addEventListener. Og ja, det er forvirrende. :-)

Men det andre problemet (som faktisk kan være ditt hovedproblem) er at DOM-globalen MouseEvent definerer target som en EventTarget, ikke som en Node. I ditt tilfelle vil det alltid være en Node (spesifikt, en Element), men slik er DOM-typen definert. For å håndtere det har du minst to valg:

Purist

Du kan gå veldig puristisk (det gjør jeg) og bruke en typepåstand-funksjon for å påstå at target er en Node:

// In a utility library:
function assertIsNode(e: EventTarget | null): asserts e is Node {
    if (!e || !("nodeType" in e)) {
        throw new Error(`Node expected`);
    }
}

// And then in your component:
const closeSelectBox = ({target}: MouseEvent): void => {
    assertIsNode(target);
    if (!searchOptionWrapRef.current?.contains(target)) {
        setOpenSelectBox(false);
    }
};

Lekerom lenke

Konsis og pragmatisk

Du vet at target er en Node og ikke er null, så du kan bruke en typepåstand (target as Node):

const closeSelectBox = ({target}: MouseEvent): void => {
    if (!searchOptionWrapRef.current?.contains(target as Node)) {
        setOpenSelectBox(false);
    }
};

Lekeromlenke

Jeg liker ikke typepåstander som ikke sjekkes under kjøring (som er hva en typepåstandsfunksjon som assertIsNode gjør), så jeg vil sannsynligvis gå for den første tilnærmingen. Men i begrensede situasjoner der du er sikker på det, kan du vurdere en.

Svar #2

Du kan påstå at instansen er av Element eller HTMLElement ved å bruke instanceof. Denne løsningen løser både kjøretid- og kompileringstid-sjekking på en minimal måte uten å forårsake unntak.

const closeSelectBox = (e: MouseEvent): void => {
  if (e.target instanceof HTMLElement && !searchOptionWrapRef.current?.contains(e.target)) {
    setOpenSelectBox(false)
  }
};

Relaterte artikler