Согласование типов реагирует.FC с ReactElement

#reactjs #typescript

Вопрос:

Вместо жесткого кодирования моих маршрутов в компоненте приложения я определил файл Routes.ts:

 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;
 

Который я затем использую следующим образом:

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

Однако, поскольку мои компоненты имеют тип React.FC , я не могу заставить их удовлетворять типу ReactElement:

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

Я пробовал:

  • Изменение компонентов на JSX.Element
  • компонент: ReactNode
  • компонент: FC

Но ни один из них не работает как типы моего компонента (FC) и тип, ожидаемый маршрутом.элемент (ReactElement) не может быть согласован.

Я даже пытался изменить component на any type, который компилируется, но приводит к ошибке во время выполнения:

 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.
 

Кто-нибудь был бы так любезен, чтобы подтолкнуть меня в правильном направлении?

Комментарии:

1. пожалуйста, предоставьте воспроизводимый пример

2. вы пытались предоставить component={route.component} вместо element=

3. harrymt.com/blog/2020/05/20/react-typescript-react-fc.html просто оставлю это здесь, может быть, будет полезно узнать

4. компонент @SinanYaman больше не существует в используемой мной версии react-router-dom, AFAIK он был переименован в element .

Ответ №1:

Чтобы ваш routes массив допускал любой тип компонента (FC или любой другой), вы можете установить тип равным be React.JSXElementConstructor . Это избавляет от необходимости определять все компоненты как FC . Этот тип принимает аргумент реквизита, но если вы не заботитесь о реквизите, вы можете просто установить его в any :

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

Комментарии:

1. Спасибо, это было именно то, что я искал!

Ответ №2:

Почему вы вводите свои компоненты в массив маршрутов как ReactElement ? Вы пробовали использовать FC вместо этого?

Утверждение, что это массив ReactElements, приведет к конфликту с ожидаемыми типами ReactRouters. Тем не менее, я предполагаю, что компоненты вашей страницы на самом деле являются React.Тип ФК?

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