javascript - React TypeScript & ForwardRef - Proprietatea 'ref' nu există pe tipul 'IntrinsicAttributes'


După ce am petrecut destul de mult timp luptându-mă cu tipurile și forwardRefs în React și TypeScript, sper că altcineva poate să clarifice asta pentru mine.

Construiesc un component DataList care este compus din trei părți:

  • Container pentru a deține toți ascultătorii de evenimente și logica
  • Lista în sine, un ul
  • Element de listă, un li

În cele din urmă, utilizarea ar arăta astfel:

<DataList.List ...>
  <DataList.Item ...>content</DataList.Item>
</DataList.List>

Pentru a obține funcționalitatea de care am nevoie, folosesc React.forwardRef, dar am descoperit că este dificil cu TypeScript deoarece mă chinui să tipizez corect componentele pentru a primi un ref precum și children și proprietăți suplimentare.

DataListContainer
Practic, vreau ca acest component să se ocupe doar de logică și de ascultătorii de evenimente, în timp ce returnează componentul principal DataList (afișat mai jos). Dar cheia aici este că trebuie să creez referința DataList aici și să o aloc componentului returnat.

const DataListContainer: React.FC = ({ children }) => {
  const listRef = useRef<HTMLUListElement>(null);

  return (
      <DataList ref={listRef}>{children}</DataList>
  );
};

DataList
Vreau ca componenta DataList să se ocupe doar de interfața sa și de proprietăți.

interface Props extends TestId {
  focusedItemId?: string;
}

const DataList: React.FC<Props> = React.forwardRef<HTMLUListElement, Props>(
  ({ children, focusedItemId, testId }, ref) => {
    return (
      <ul
        aria-activedescendant={focusedItemId}
        data-test-id={testId}
        ref={ref}
      >
        {children}
      </ul>
    );
  },
);

Totuși, asta nu este tocmai corect. Această configurare îmi dă eroarea

Type '{ children: any[]; ref: RefObject<HTMLUListElement>; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
  Property 'ref' does not exist on type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.

Răspuns #1

Ești aproape acolo! Urmând Cheatsheet-ul React TypeScript, problema este cu proprietățile DataList. Adăugarea proprietății children ar rezolva problema

interface Props extends TestId {
  children?: ReactNode;
  focusedItemId?: string;
}

Am recreat un exemplu simplu în acest CodeSandbox