React Router предоставляет мощный механизм для организации маршрутизации в приложениях на React. Однако при построении крупных приложений становится критически важной строгая типизация навигации для предотвращения ошибок при передаче параметров, формировании URL и работе с историей навигации. Использование TypeScript совместно с React Router позволяет обеспечить безопасное взаимодействие между компонентами и маршрутами на этапе компиляции.
В React Router маршруты определяются с помощью компонента
<Route>. Основные параметры маршрута —
path, element и children. Для
строгой типизации можно определить объект с маршрутами и их
параметрами:
interface RouteParams {
home: {};
user: { userId: string };
settings: { tab?: string };
}
type RouteKey = keyof RouteParams;
const routes: Record<RouteKey, string> = {
home: "/",
user: "/user/:userId",
settings: "/settings/:tab?"
};
Ключевые моменты:
Record<RouteKey, string> связывает ключ маршрута
с шаблоном URL.RouteParams описывают обязательные и
опциональные параметры.:param) обеспечивает
согласованность с определением маршрута.Для безопасной навигации применяется useNavigate с
вспомогательной функцией, которая учитывает параметры:
import { useNavigate } from "react-router-dom";
function useTypedNavigate() {
const navigate = useNavigate();
return function <T extends RouteKey>(
route: T,
params: RouteParams[T]
) {
let path = routes[route];
for (const key in params) {
if (params[key]) {
path = path.replace(`:${key}`, params[key] as string);
}
}
navigate(path);
};
}
Особенности подхода:
RouteParams.React Router предоставляет хук useParams для получения
параметров маршрута. Для строгой типизации можно использовать
дженерики:
import { useParams } from "react-router-dom";
function UserPage() {
const params = useParams<{ userId: string }>();
return <div>User ID: {params.userId}</div>;
}
Преимущества:
any и последующие ошибки
времени выполнения.Для работы с query-параметрами используется объект
URLSearchParams. Строгая типизация возможна через отдельные
интерфейсы:
interface UserQuery {
showDetails: boolean;
}
function useTypedQuery<T>() {
const params = new URLSearchParams(window.location.search);
return new Proxy(params, {
get(target, prop: string) {
const value = target.get(prop);
return typeof value === "string" ? value : undefined;
}
}) as unknown as T;
}
function UserPage() {
const query = useTypedQuery<UserQuery>();
if (query.showDetails) {
return <div>Подробности пользователя</div>;
}
return <div>Общая информация</div>;
}
Заметки по реализации:
React Router позволяет передавать состояние через
navigate:
interface NavigationState {
fromDashboard?: boolean;
}
const navigate = useNavigate();
navigate("/settings", { state: { fromDashboard: true } });
Для строгой типизации рекомендуется использовать дженерики:
function useTypedNavigateState<T>() {
const navigate = useNavigate();
return (path: string, state: T) => navigate(path, { state });
}
const typedNavigate = useTypedNavigateState<NavigationState>();
typedNavigate("/settings", { fromDashboard: true });
Преимущества:
useLocation.Использование типизированных маршрутов облегчает построение
компонента <Routes>:
import { Routes, Route } from "react-router-dom";
function AppRoutes() {
return (
<Routes>
<Route path={routes.home} element={<HomePage />} />
<Route path={routes.user} element={<UserPage />} />
<Route path={routes.settings} element={<SettingsPage />} />
</Routes>
);
}
Преимущества:
routes.Строгая типизация навигации в React Router позволяет:
Такой подход особенно важен для крупных приложений с множеством динамических маршрутов, где контроль типов становится ключевым инструментом стабильной разработки.