TypeScript中如何實現(xiàn)類型安全的路由系統(tǒng)
在 TypeScript 中實現(xiàn)一個類型安全的路由系統(tǒng),可以通過 類型推導 和 類型約束 來確保路由路徑、參數、查詢參數和組件類型之間的強一致性。以下是實現(xiàn)一個類型安全路由系統(tǒng)的完整方案:
目標
- 路由路徑類型安全(路徑錯誤編譯時報錯)
- 路由參數類型安全(路徑參數類型正確)
- 查詢參數類型安全(查詢參數類型正確)
- 路由組件類型安全(路由組件類型正確)
- 支持嵌套路由
1. 定義路由類型結構
我們使用一個 RouteConfig 類型來定義路由結構,支持嵌套和參數。
type RouteConfig<T extends string> = {
path: T;
component: React.ComponentType<any>;
children?: RouteConfig<any>[];
params?: Record<string, string>; // 可選參數類型
query?: Record<string, string>; // 查詢參數類型
};
但更推薦使用 泛型 + 映射類型 來實現(xiàn)類型安全。
2. 使用infer和Extract實現(xiàn)路徑參數類型推導
我們使用 infer 來從路徑字符串中提取參數類型。
// 從路徑字符串中提取參數類型
type PathParams<T extends string> = T extends `${infer P}/${infer R}`
? P extends `:${infer Param}`
? { [K in Param]: string } & PathParams<R>
: PathParams<R>
: {};
示例:
type P1 = PathParams<'users/:id'>; // { id: string }
type P2 = PathParams<'users/:id/posts/:postId'>; // { id: string; postId: string }
3. 定義路由配置類型(支持嵌套)
type Route<T extends string> = {
path: T;
component: React.ComponentType<any>;
children?: Route<T>[];
params?: PathParams<T>; // 參數類型
query?: Record<string, string>; // 查詢參數類型
};
4. 創(chuàng)建路由表(類型安全)
const routes = {
home: {
path: '/',
component: Home,
},
users: {
path: '/users',
component: Users,
children: [
{
path: '/users/:id',
component: UserDetail,
params: { id: 'string' },
},
{
path: '/users/:id/posts/:postId',
component: PostDetail,
params: { id: 'string', postId: 'string' },
},
],
},
} as const;
使用
as const強制類型推導為字面量類型,防止類型丟失。
5. 實現(xiàn)類型安全的useNavigate和useLocation
useNavigate類型安全
type NavigateOptions<T extends string> = {
to: T;
query?: Record<string, string>;
};
function useNavigate() {
const navigate = useNavigate(); // 假設使用 React Router v6
return <T extends string>(options: NavigateOptions<T>) => {
const { to, query } = options;
const search = query ? new URLSearchParams(query).toString() : '';
navigate(`${to}${search ? `?${search}` : ''}`);
};
}
useLocation類型安全
function useLocation<T extends string>() {
const location = useLocation();
const path = location.pathname as T;
// 提取路徑參數
const params = path.split('/').reduce((acc, segment, index, arr) => {
if (segment.startsWith(':')) {
const key = segment.slice(1);
const value = arr[index + 1];
return { ...acc, [key]: value };
}
return acc;
}, {} as Record<string, string>);
// 查詢參數
const searchParams = new URLSearchParams(location.search);
const query = {} as Record<string, string>;
searchParams.forEach((value, key) => {
query[key] = value;
});
return { path, params, query };
}
6. 使用useNavigate和useLocation的示例
function UserDetail() {
const { params, query } = useLocation<'/users/:id'>();
const navigate = useNavigate();
return (
<div>
User: {params.id}
<button onClick={() => navigate({ to: '/users', query: { page: '2' } })}>
Go to Users
</button>
</div>
);
}
7. 類型安全的Link組件
type LinkProps<T extends string> = {
to: T;
query?: Record<string, string>;
children: React.ReactNode;
};
function Link<T extends string>({ to, query, children }: LinkProps<T>) {
const navigate = useNavigate();
return (
<button onClick={() => navigate({ to, query })}>
{children}
</button>
);
}
8. 使用React Router的類型安全封裝
如果你使用 react-router-dom,可以使用 useParams 和 useSearchParams 并結合類型推導。
function UserDetail() {
const { id } = useParams<{ id: string }>();
const [searchParams] = useSearchParams();
const postId = searchParams.get('postId');
return <div>User {id} Post {postId}</div>;
}
useParams和useSearchParams本身支持類型推導,但需要手動指定類型。
9. 高級:使用zod+TypeScript實現(xiàn)查詢參數驗證
import { z } from 'zod';
const UserQuerySchema = z.object({
page: z.string().optional(),
limit: z.string().optional(),
});
type UserQuery = z.infer<typeof UserQuerySchema>;
然后在 useLocation 中使用:
const query = UserQuerySchema.parse(Object.fromEntries(searchParams));
10. 總結:類型安全路由系統(tǒng)的關鍵點
| 功能 | 實現(xiàn)方式 |
|---|---|
| 路徑類型安全 | 使用 infer 提取路徑參數 |
| 參數類型安全 | params 字段顯式定義類型 |
| 查詢參數類型安全 | query 字段定義類型,配合 zod 驗證 |
| 組件類型安全 | component 類型為 React.ComponentType<any> |
| 路由跳轉安全 | useNavigate 類型約束 to 路徑 |
| 嵌套路由 | 使用 children 字段遞歸定義 |
最終建議
- 使用
React Router v6或Next.js App Router(推薦) - 使用
zod驗證查詢參數 - 使用
as const固定路由配置類型 - 使用
infer提取路徑參數類型 - 使用
useNavigate和useLocation封裝類型安全接口
示例項目結構
src/
routes/
index.ts
user.ts
components/
Home.tsx
UserDetail.tsx
hooks/
useNavigate.ts
useLocation.ts
通過以上方式,你可以構建一個 完全類型安全 的路由系統(tǒng),避免運行時錯誤,提升開發(fā)體驗。
到此這篇關于TypeScript中如何實現(xiàn)類型安全的路由系統(tǒng)的文章就介紹到這了,更多相關TypeScript實現(xiàn)路由系統(tǒng)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
微信小程序事件對象中e.target和e.currentTarget的區(qū)別詳解
這篇文章主要介紹了微信小程序事件對象中e.target和e.currentTarget的區(qū)別詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05
利用純js + transition動畫實現(xiàn)移動端web輪播圖詳解
這篇文章主要給大家介紹了利用純js + transition動畫實現(xiàn)移動端web輪播圖的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考借鑒,下面來一起看看吧。2017-09-09
JavaScript 進度條實現(xiàn)代碼(Firefox等相似瀏覽器下不支持)
JavaScript實現(xiàn)的進度條,可惜在Firefox等相似瀏覽器下不支持(遠程)2009-07-07
childNodes.length與children.length的區(qū)別
childNodes.length與children.length的值常不一樣。2009-05-05

