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

1.6k views Asked by At

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:

  • @types/react": "^17.0.5"
  • @types/react-dom": "^17.0.0"
  • react": "^17.0.2"
  • react-dom": "^17.0.2"
  • react-router-dom": "^5.2.0"

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

1

There are 1 answers

0
somallg On BEST ANSWER

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.