React Router предоставляет гибкий механизм для организации маршрутов в приложениях на React, однако при работе с TypeScript и большими приложениями особенно важно правильно типизировать маршруты. Типизация маршрутов повышает безопасность кода, упрощает поддержку и минимизирует ошибки при навигации и передаче параметров.
Маршруты в React Router задаются с помощью компонентов
<Routes> и <Route>. Для типизации
маршрутов обычно создают централизованную структуру, где каждому
маршруту соответствует ключ и параметры.
interface RouteParams {
userId?: string;
postId?: string;
}
interface AppRoutes {
HOME: { path: "/" };
USERS: { path: "/users" };
USER_DETAILS: { path: "/users/:userId"; params: { userId: string } };
POSTS: { path: "/posts" };
POST_DETAILS: { path: "/posts/:postId"; params: { postId: string } };
}
const routes: AppRoutes = {
HOME: { path: "/" },
USERS: { path: "/users" },
USER_DETAILS: { path: "/users/:userId", params: { userId: "" } },
POSTS: { path: "/posts" },
POST_DETAILS: { path: "/posts/:postId", params: { postId: "" } },
};
Ключевой момент: определение параметров маршрута через отдельное поле
params позволяет TypeScript проверять наличие и типы этих
параметров на этапе компиляции.
useParams с типамиReact Router предоставляет хук useParams для получения
динамических сегментов URL. При типизации важно указывать интерфейс с
ожидаемыми параметрами:
import { useParams } from "react-router-dom";
interface UserParams {
userId: string;
}
function UserPage() {
const { userId } = useParams<UserParams>();
return <div>Пользователь с ID: {userId}</div>;
}
Типизация useParams<UserParams>() гарантирует, что
TypeScript предупредит о попытках доступа к несуществующим или
неправильно типизированным параметрам.
Link и navigateДля навигации используется компонент <Link> и хук
useNavigate. При типизации маршрутов можно создать
вспомогательную функцию для генерации URL с проверкой параметров:
import { generatePath } from "react-router-dom";
function buildPath<T extends keyof AppRoutes>(
route: T,
params?: AppRoutes[T] extends { params: infer P } ? P : never
) {
return params ? generatePath(routes[route].path, params) : routes[route].path;
}
// Пример использования
<Link to={buildPath("USER_DETAILS", { userId: "123" })}>Профиль пользователя</Link>
Такой подход позволяет TypeScript проверять соответствие переданных параметров маршруту и предотвращает ошибки типа “не передан обязательный параметр”.
В крупных приложениях удобно создавать единую конфигурацию маршрутов с компонентами и правами доступа:
interface RouteConfig<PathParams = undefined> {
path: string;
element: React.ReactNode;
children?: RouteConfig[];
params?: PathParams;
requiresAuth?: boolean;
}
const routeConfig: RouteConfig[] = [
{ path: "/", element: <HomePage /> },
{ path: "/users", element: <UsersPage /> },
{ path: "/users/:userId", element: <UserPage />, params: { userId: "" }, requiresAuth: true },
];
Использование такой конфигурации позволяет строить маршруты динамически и типобезопасно:
function renderRoutes(routes: RouteConfig[]) {
return routes.map(({ path, element, children }) => (
<Route key={path} path={path} element={element}>
{children && renderRoutes(children)}
</Route>
));
}
TypeScript проверяет наличие необходимых полей и корректность параметров, снижая вероятность ошибок при масштабировании приложения.
Для удобства можно создать вспомогательный тип, который автоматически извлекает параметры маршрутов:
type RouteParams<T extends keyof AppRoutes> =
AppRoutes[T] extends { params: infer P } ? P : never;
// Пример
const userPath: string = buildPath("USER_DETAILS", { userId: "42" }); // корректно
const invalidPath = buildPath("USER_DETAILS"); // ошибка компиляции
Такой подход делает маршруты полностью типобезопасными, гарантируя соответствие URL и передаваемых параметров.
Эти подходы позволяют создавать надежные, масштабируемые приложения на React с гарантированной корректностью маршрутизации и строгой типизацией всех URL-параметров.