Home > Blockchain >  Reconciling types React.FC with ReactElement
Reconciling types React.FC with ReactElement

Time:11-09

Instead of hard-coding my routes in my App component, I've defined a Routes.ts file:

import Login from "../components/Login/Login";
import Dashboard from "../components/Dashboard/Dashboard";
import PageNotFound from "../components/PageNotFound/PageNotFound";
import {ReactElement, ReactNode} from "react";

const routes: Array<{
    path: string,
    component: ReactElement,
    is_private: boolean
}> = [
    {
        path: '/',
        component: Login,
        is_private: false
    },
    {
        path: '/dashboard',
        component: Dashboard,
        is_private: true
    },
    {
        path: '/*',
        component: PageNotFound,
        is_private: false
    }
];

export default routes;

Which I then use like so:

const App: React.FC = () => {
  return (
    <div className="wrapper">
      <h1>My App</h1>
      <BrowserRouter>
        <Routes>
            {routes.map((route) => (
                <Route path={route.path}
                       key={route.path}
                       element={route.component} />
            ))}
        </Routes>
      </BrowserRouter>
    </div>
  );
}

However, since my components are of type React.FC I can't get them to satisfy the ReactElement type:

TS2739: Type 'FunctionComponent<{}>' is missing the following properties from type 'ReactElement<any, string | JSXElementConstructor<any>>': type, props, key 

I've tried:

  • Changing the components to JSX.Element
  • component: ReactNode
  • component: FC

But none of those work as the types of my component (FC) and the type expected by Route.element (ReactElement) are not reconcilable.

I've even tried changing component to any type, which does compile, but results in runtime error:

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.

Would anyone be so kind to nudge my in the right direction?

CodePudding user response:

To make your routes array allow any kind of component (FC, or otherwise), you can set the type to be React.JSXElementConstructor. This prevents the need to define all components as FC. This type takes an argument of the props, but if you don't care about the props, you can just set it to any:

const routes: Array<{
    path: string,
    component: React.JSXElementConstructor<any>,
    is_private: boolean
}> = [

CodePudding user response:

Why do you type your components in your routes array as ReactElement? Have you tried using FC instead?

Stating that this is an array of ReactElements will clash with ReactRouters expected types. However, I guess your page components are in fact of React.FC type?

import Login from "../components/Login/Login";
import Dashboard from "../components/Dashboard/Dashboard";
import PageNotFound from "../components/PageNotFound/PageNotFound";
import {FC, ReactNode} from "react";

const routes: Array<{
    path: string,
    component: FC,
    is_private: boolean
}> = [
    {
        path: '/',
        component: Login,
        is_private: false
    },
    {
        path: '/dashboard',
        component: Dashboard,
        is_private: true
    },
    {
        path: '/*',
        component: PageNotFound,
        is_private: false
    }
];


const App: React.FC = () => {
  return (
    <div className="wrapper">
      <h1>My App</h1>
      <BrowserRouter>
        <Routes>
            {routes.map((route) => (
                <Route path={route.path}
                       key={route.path}
                       element={route.component as } />
            ))}
        </Routes>
      </BrowserRouter>
    </div>
  );
}
  • Related