reactjstypescriptreact-routerhigh-order-component

Unable to use HOC with React-Router: Type 'Element' is not assignable to type 'ComponentType<any>


I have a High Order Function with React-Router, but cannot make it work, neither this way or using

return class extends React.Component { render{ ... }

export const withHeaderAndFooter = (component: ComponentType) => {
  return (
    <div className="flex flex-col h-full">
      <Header />
      {component}
      <Footer />
    </div>
  );
};


But this fails with: Type 'Element' is not assignable to type 'ComponentType<any>

import { withHeaderAndFooter } from "./layout";

// prettier-ignore
const App = () => {
  return (
    <Router>
        <Switch>
          <Route path="/" exact component={withHeaderAndFooter(Home)} />
          <Route path="/login" component={withHeaderAndFooter(Login)} />
          <Route path="*" component={NotFound} />
        </Switch>
    </Router>
  );
};

And this fails with: index.js:1 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.

const App = () => {
  return (
    <Router>
        <Switch>
          <Route path="/" exact component={() => withHeaderAndFooter(Home)} />
          <Route path="/login" component={() => withHeaderAndFooter(Login)} />
          <Route path="*" component={NotFound} />
        </Switch>
    </Router>
  );
};

I am using:

Related: HOC : Type 'Element' is not assignable to type 'FC<P>'


Solution

  • The syntax you use to render the component is wrong

    export const withHeaderAndFooter = (component: ComponentType) => {
      return (
        <div className="flex flex-col h-full">
          <Header />
          {component} <- wrong syntax
          <Footer />
        </div>
      );
    };
    

    Correct syntax to render a Component:

    export const withHeaderAndFooter = (Component: ComponentType) => {
      return (
        <div className="flex flex-col h-full">
          <Header />
          <Component />
          <Footer />
        </div>
      );
    };
    

    Notice first character of the variable name must be in uppercase to inform JSX parser that variable is a custom React Component not a HTML tag.