javascript - Cum pot să trec Componenta A cu proprietăți generice în componenta B ca o proprietate opțională


Scriu un component personalizat select (SelectBase) cu o funcție de a înlocui componentele de bază create în interiorul componentului de bază. De exemplu, dacă nu transmit un ModalComponent în interiorul SelectBase, voi folosi BaseModalComponent.

Problema este că proprietățile prop-ului ModalComponent sunt necunoscute și vreau să fac posibilă trecerea proprietăților ModalComponent în interiorul SelectBase atunci când folosesc SelectBase cu ModalComponent personalizat.

const SomeSelectInstance = SelectBase<ISomeSelectInstanceProps>;

M-am oprit la următoarea interfață a SelectBase:

import { ComponentType } from 'react';
import { Drawer } from '@mui/material';

interface ISelectBaseProps<ModalProps> {
  open: boolean;
  modalRenderMode: 'desktop' | 'mobile'
  ModalComponent?: ComponentType<ModalProps>;
  ModalComponentProps?: ModalProps;

În interiorul SelectBase trebuie să folosesc Drawer sau un BaseMenuList personalizat în funcție de valoarea modalRenderMode:

  const BaseModalComponent = modalRenderMode === 'desktop' ? BaseMenuList : Drawer;

  const Modal = ModalComponent ?? BaseModalComponent;

  const modalElement = <Modal {...ModalComponentProps}>{children}</Modal>; // here I get Error

Eroarea pe care o primesc: „Tipul „{ children: ReactNode; }” nu poate fi atribuit tipului „ModalProps”

Cod complet SelectBase:

import { ComponentType, ReactNode, useRef, useState } from 'react';

import { Drawer, PopoverProps, SelectProps } from '@mui/material';
import { IconSelectArrow } from 'icons';
import { BaseMenuList } from 'portfolio3/ui-kit';
import { BaseMenuItem } from 'portfolio3/ui-kit/menu';
import { IInputBaseProps, StyledSelectBase } from 'portfolio3/ui-kit/selects/bases';
import { InputRenderMode } from 'portfolio3/ui-kit/types';

export interface ISelectBaseProps extends SelectProps {
  inputRenderMode: InputRenderMode; // переименовать в inputRenderMode
}

interface ISelectBasePropss<ModalProps> {
  inputRenderMode: InputRenderMode;
  modalRenderMode: 'desktop' | 'mobile';
  open: boolean;
  onClick: () => void;
  onClose: PopoverProps['onClose'];
  type?: 'select' | 'input';
  ModalComponent?: ComponentType<ModalProps>;
  InputComponent?: ComponentType<IInputBaseProps>;
  ModalComponentProps?: ModalProps;
  InputComponentProps?: IInputBaseProps;
  children: ReactNode;
}

// eslint-disable-next-line prettier/prettier
const SelectBase = <ModalProps, >({
  inputRenderMode,
  modalRenderMode,
  open,
  onClick,
  onClose,
  InputComponent,
  ModalComponent,
  ModalComponentProps,
  InputComponentProps,
  children,
  type = 'select',
}: ISelectBasePropss<ModalProps>) => {
  const selectRef = useRef<HTMLDivElement>(null);

  const inputProps: IInputBaseProps = {
    ...InputComponentProps,
    rendermode: inputRenderMode,
    ref: selectRef,
    onClick,
    readOnly: type === 'select',
    inputProps: {
      style: {
        cursor: type === 'select' ? 'pointer' : 'initial',
      },
    },
  };

  const modalProps: ModalProps = {
    ...ModalComponentProps,
    open,
    anchorEl: selectRef.current,
    onClose,
  };

  const inputElement = InputComponent ? <InputComponent {...inputProps} /> : <StyledSelectBase {...inputProps} />;

  const BaseModalComponent = modalRenderMode === 'desktop' ? BaseMenuList : Drawer;

  const Modal = ModalComponent ?? BaseModalComponent;

  const modalElement = <Modal {...modalProps}>{children}</Modal>;

  return (
    <div className="select-base">
      {inputElement}
      {modalElement}
    </div>
  );
};

export default SelectBase;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Cum pot rezolva asta sau poate există o variantă mai bună sau mai optimizată?