Categories
Tags
Ai 生成 API学习 API简化 api请求 API调用 best-practices Blogging Caching catchTag catchTags class CLI Config context Context Context.Tag CSS Customization Demo development DocC dual API effect Effect Effect.Service Effect.succeed Example extension filterOrFail flatMap Fuwari gen generator grep hooks HTML HTTP响应 IDE自动补全 iOS javascript JavaScript Javascript Layer.effect Layer.provide Layers Linux Markdown Mock Next.js ParseError pipe pokemon PostCSS process.env progress Promise promise provideService PWA react React React Hook Form React Query React Router react-native Scheduler Schema Schema.Class security Service Worker Services SSR state-management suspense Tagged Errors TaggedError TanStack Query TanStack Start tips tryPromise tsconfig TypeScript typescript Video VS Code vscode Web API Web Development yield Zod 不透明类型 二叉树 代码组织 任务调度 优先级 使用服务 依赖注入 依赖管理 值语义 入门教程 最佳实践 最小堆 函数式编程 函数组合 前端 前端开发 副作用 副作用控制 可视化 可组合性 可维护性 可访问性 命令行 响应过滤 多个错误 实现 实践指南 层 层依赖 层组合 工具链 并发控制 应用架构 延迟执行 开发技巧 开发教程 开源 异步处理 异步操作 异步编程 性能优化 手写系列 排序 接口设计 插件开发 数据结构 数据获取 数据解码 数据验证 无限滚动 日历 日志分析 服务 服务依赖 服务定义 服务实现 服务提供 测试 源码分析 状态管理 环境变量 生成器 离线支持 程序分离 算法 类型安全 类型定义 类型推断 类型系统 类定义 线性代码 组合 翻译 自定义错误 表单验证 记忆化 设计模式 语义化 运维 运行时验证 部分应用 配置 配置变量 配置服务 配置管理 重构 错误处理 错误定义 错误恢复 项目设置
879 words
4 minutes
使用 TypeScript 和 React Router 进行安全导航
为什么基于字符串的路由会失败
const navigate = useNavigate(); // 应用中的某处 navigate('/dashboard/items/42/edit'); // 应用中的其他地方 navigate('/dashboard/items/' + itemId + '/edit'); // 糟糕,拼写错误 navigate('/dasboard/items/42/edit'); // 404
在基于字符串的路由中,路径只是字符串。TypeScript 无法验证它们,提供自动完成功能,或警告你有拼写错误。如果你重命名路由或重构 URL 结构,应用可能会悄无声息地崩溃 — 在拥有数百个路由的大型应用中尤其痛苦。
什么是类型安全路由?
类型安全路由用类型化的路由构建器和经过验证的参数替代脆弱的字符串。不再是这样写:
navigate('/dashboard/items/42/edit');
而是这样写:
navigate(routes.dashboard.items.edit({ id: '42' }));
现在,TypeScript 会验证:
- /dashboard/items/edit 是一个有效的路径
- id 参数是必需的且类型正确
- 路由结构的任何更改都会反映在整个应用中
好处包括:
- IDE 自动完成
- 编译时验证
- 更简单、更安全的重构
使用 React Router v6 和 TypeScript 的基本设置
首先定义所有可能的路由及其参数类型:
interface AppRoutes { '/': {}; '/dashboard': {}; '/dashboard/items': {}; '/dashboard/items/:id': { id: string }; '/dashboard/items/:id/edit': { id: string }; }
现在创建一个类型安全的导航钩子:
import { useNavigate } from 'react-router-dom'; function useTypedNavigate<T extends keyof AppRoutes>() { const navigate = useNavigate(); return (path: T, params?: AppRoutes[T]) => { let url = path as string; if (params) { for (const [key, value] of Object.entries(params)) { url = url.replace(`:${key}`, value); } } navigate(url); }; }
你还可以为路由参数安全性类型化 useParams:
import { useParams } from 'react-router-dom'; function useTypedParams<T extends keyof AppRoutes>() { return useParams() as AppRoutes[T]; } // 使用方法 const { id } = useTypedParams<'/dashboard/items/:id/edit'>();
集中管理路由
export const routeConfig = { home: '/', dashboard: { root: '/dashboard', items: { list: '/dashboard/items', edit: '/dashboard/items/:id/edit', create: '/dashboard/items/new', }, }, } as const;
使用 TypeScript 的推断功能自动派生路径类型,减少重复并确保一致性。
使用现代库
如果你正在构建大型应用,考虑使用那些开箱即支持类型化路由的库:
示例:TanStack Router
const itemEditRoute = new Route({ getParentRoute: () => dashboardRoute, path: '/items/$itemId/edit', component: ItemEdit, }); function ItemEdit() { const { itemId } = itemEditRoute.useParams(); // itemId 的类型为 string }
渐进式采用策略
你不需要一次性重写整个应用。相反:
- 为新功能引入 useTypedNavigate 和 useTypedParams
- 逐步重构旧组件
- 使用 lint 规则强制保持一致性
ESLint 示例:
"rules": { "no-hardcoded-routes": "error" }
这条规则防止在导航中使用原始字符串,强制执行你的类型化路由系统。
类型化路由的亮点
类型安全路由在以下场景特别有用:
- 管理仪表板:数十个视图和深度链接
- 电子商务应用:动态过滤器和嵌套路由
- 带有状态 URL 的单页应用:与 Redux、Zustand 或基于 URL 的状态集成
示例:
interface ECommerceRoutes { '/shop': {}; '/shop/:category': { category: string }; '/shop/:category/:itemId': { category: string; itemId: string }; '/checkout': {}; }
与状态管理器集成,如 Zustand:
const useStore = create((set) => ({ currentRoute: '/', navigateTo: (route: keyof AppRoutes) => set({ currentRoute: route }), }));
最终思考
类型安全导航正在成为现代 React 开发的标准。它提高了信心,防止运行时故障,并使重构变得无痛 — 尤其是在大型应用中。
如果你的应用仍然依赖基于字符串的路径,你可能在浪费时间调试可预防的问题。采用类型化路由意味着减少因单个拼写错误的 URL 而导致的周五晚上部署灾难。
使用 TypeScript 和 React Router 进行安全导航
https://0bipinnata0.my/posts/weekly-translate/navigate-safely-with-typescript-and-react-router/

