2

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?

4
  • 1
    pls provide reproducible example Commented Nov 8, 2021 at 11:38
  • did you try providing component={route.component} instead of element= Commented Nov 8, 2021 at 11:41
  • harrymt.com/blog/2020/05/20/react-typescript-react-fc.html just dropping this here, might be helpful to know Commented Nov 8, 2021 at 11:58
  • 1
    @SinanYaman component no longer exists in the react-router-dom version I'm using, AFAIK it has been renamed to element. Commented Nov 8, 2021 at 12:11

2 Answers 2

1

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
}> = [
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, that was exactly what I was looking for!
0

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>
  );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.