Compound Components - React Typescript

Viewed 4010

I'm trying to use React Typescript with Compound Components, but I'm having this error:

JSX element type 'Nav.Content' does not have any construct or call signatures.ts(2604)

Here is a sandbox: https://codesandbox.io/s/compound-components-typescript-fjilh?file=/src/App.tsx

Any idea how can I fix it?

This is how my code looks:

Nav.tsx

interface ContentProps {
  children: ReactNode;
}
const Content: React.FC<ContentProps> = (props: ContentProps) => (
  <div>{props.children}</div>
);
interface ContentComposition {
  Content?: React.FC<ContentProps>;
}
interface Props {
  children: ReactNode;
}
const Nav: React.FC<Props> & ContentComposition = (props: Props) => (
  <div>{props.children}</div>
);

Nav.Content = Content;

export default Nav;

App.tsx

export default function App() {
  return (
    <div className="App">
      <Nav>
        <Nav.MainContent>
          <h2>Start editing to see some magic happen!</h2>
        </Nav.MainContent>
        <h1>Hello CodeSandbox</h1>
      </Nav>
    </div>
  );
}

2 Answers

Thanks to Brady from Reactiflux I was able to find the answer.

The issue was that I was using React.FC

More info about React.FC here: https://github.com/typescript-cheatsheets/react-typescript-cheatsheet#function-components

Here is the answer:

interface ContentProps {
  children: ReactNode;
}
const Content = (props: ContentProps) => <div>{props.children}</div>;

interface Props {
  children: ReactNode;
}
const Nav = (props: Props) => <div>{props.children}</div>;

Nav.Content = Content;

export default Nav;

One way to address this is the following:

import React, { FC } from 'react';

interface SubComponentProps {
    /* ... */    
}
const SubComponent: FC<SubComponentProps> = () => {
    /* ... */
};

interface ParentComposition {
    Sub: typeof SubComponent; /* or you can do FC<SubComponentProps> */
}

interface ParentProps {
    /* ... */
}
const Parent: FC<ParentProps> & ParentComposition = () => {
    /* .... */
};

Parent.Sub = SubComponent;

export default Parent;

The key here is to use the Composition interface and use it when declaring the compound component type.

Related