I have a Panel component that optionally allows the user to use compound components. The panel has a default header that contains the close functionality (button) and the main reason I did this is was to give the user the option to use a custom header with their own button and whatever else they would like, so I opted to use compound components and to allow the Panel component to check for the existence of the component in its children and if so, it will not use the default header. I have it all working but I can't seem to figure out how to get the Typescript error to clear.
Below is the code pertaining to Typescript and the error I'm getting. I also linked to a sandbox with the working code with errors.
I have tried tons of variations from Google searches and in a days time cannot find the solution.
Sandbox: https://codesandbox.io/s/panel-513yq?file=/src/Panel/Panel.tsx:510-4061
App.js:
export default function App() {
const [open, setOpen] = React.useState(false);
const handleClose = () => {
setOpen(false);
};
const handleOpen = () => {
setOpen(true);
};
return (
<div id="page" data-test-id="component-app">
<header id="header">
<button onClick={handleOpen}>Open</button>
</header>
<main id="main">
<Panel open={open} onClosed={handleClose} renderPortal={true}>
<Panel.Header>
<div>
<button onClick={handleClose}>Close</button>
</div>
</Panel.Header>
<Panel.Content>Panel Content</Panel.Content>
</Panel>
</main>
</div>
);
}
Panel Component:
interface ModalPropsComposition {
Header?: React.FC<PanelHeaderProps>;
Content?: React.FC<PanelContentProps>;
}
export interface PanelProps
extends React.HTMLAttributes<HTMLDivElement>,
ModalPropsComposition {
open: boolean;
position?: string;
renderPortal?: boolean;
// Lifecycle callbacks
onClose?: () => void;
onClosed?: () => void;
onOpen?: () => void;
onOpened?: () => void;
}
/**
* @Codeannex UI React: Panel Component
*
* Panel Component
*/
const _Panel = ({
children,
open,
renderPortal,
onClose,
onClosed,
onOpen,
onOpened
}: PanelProps & { forwardedRef: React.Ref<HTMLDivElement> }): JSX.Element => {
// panel code...
};
export const Panel = React.forwardRef(
(props: PanelProps, ref: React.Ref<HTMLDivElement>): JSX.Element => {
return <_Panel {...props} forwardedRef={ref} data-testid={PANEL_TEST_ID} />;
}
);
Panel.Header = PanelHeader;
Panel.Content = PanelContent;
Error:

You can fix this error by using Object.assign. This works because Object.assign is typed as assign<T, U>(target: T, source: U): T & U;, so the types T and U can be inferred, and the return type becomes a mix of the forwardRef exotic component type and the object with Header and Content properties.
export const Panel = Object.assign(
React.forwardRef(
(props: PanelProps, ref: React.Ref<HTMLDivElement>): JSX.Element => {
return (
<PanelComponent
{...props}
forwardedRef={ref}
data-testid={PANEL_TEST_ID}
/>
);
}
),
{
Header: PanelHeader,
Content: PanelContent
}
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With