2

In this MainHeader component:

<MainHeader
  LeftButton={
    previous ? (
      <BackButton
        onPress={() => {
          navigation.goBack;
        }}
      />
    ) : (
      undefined
    )
  }
  ...
/>

BackButton is a JSX element passed down through the LeftButton prop to MainHeader and is explicitly typed as const BackButton: React.FC<BackButtonProps>, so then I would expect the LeftButton prop to be typed as follows:

interface MainHeaderProps {
  LeftButton: React.FC<any> | undefined;
  ...
}

But I get this error when trying to assign BackButton | undefined to the LeftButton prop: Type 'Element | undefined' is not assignable to type 'FC<any> | undefined'. ...so I change my type to

interface MainHeaderProps {
  LeftButton: JSX.Element | undefined;
  ...
}

Error goes away. But now I get an error when I try to use <LeftButton /> in MainHeader: JSX element type 'LeftButton' does not have any construct or call signatures. So after doing some reading I'm even more confused about what type I should be using... I try many different types from @types/react like ComponentType to try and define LeftButton by its constructor, but TypeScript enforces that LeftButton be typed as JSX.Element, so I'm not sure how to best resolve this.

Malcolm McSwain
  • 1,888
  • 2
  • 15
  • 17

2 Answers2

5

React.FC<any> is the type of a functional component. A function that returns rendered JSX.

JSX.Element is the type of the return value of a functional component, already rendered.

So you can use JSX.Element, pass in your component as are you already doing, and then display it simply with this, since you already pass in props and rendered it.

<div>{props.LeftButton}</div>
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
3

If your intent is to either render or not render something - use null not undefined. null tells react not to render anything.

So:

<MainHeader
  LeftButton={
    previous ? (
      <BackButton
        onPress={() => {
          navigation.goBack;
        }}
      />
    ) : null
  }
  ...
/>

You can also:

<MainHeader
  LeftButton={
    previous && (
      <BackButton
        onPress={() => {
          navigation.goBack;
        }}
      />
    )
  }
  ...
/>

As for the types. What you do is most commonly done using:

interface MainHeaderProps {
  LeftButton: React.ReactElement;
  ...
}

See, for instance MUI Tab component typings. As you'll also see ReactNode is also an option, differences described in this SO answer.

Izhaki
  • 23,372
  • 9
  • 69
  • 107
  • Thanks for your answer. I still get the exact same issue when typed as React.ReactElement instead of JSX.Element: "JSX element type 'LeftButton' does not have any construct or call signatures." How do I resolve this? – Malcolm McSwain Jan 03 '20 at 22:50
  • Fixed: I was calling the prop incorrectly. {} instead of just {LeftButton} New to functional components. – Malcolm McSwain Jan 03 '20 at 22:53