欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

TypeScript中如何實(shí)現(xiàn)類型安全的路由系統(tǒng)

 更新時(shí)間:2025年10月25日 14:51:14   作者:代碼保安  
本文講述TypeScript如何實(shí)現(xiàn)類型安全的路由系統(tǒng),路由類型結(jié)構(gòu)、使用infer和Extract提取參數(shù)類型、定義路由配置類型、創(chuàng)建路由表、實(shí)現(xiàn)類型安全的導(dǎo)航和位置鉤子等,使用React?Router?v6或Next.js?App?Router,結(jié)合zod進(jìn)行查詢參數(shù)驗(yàn)證,以實(shí)現(xiàn)類型安全的路由系統(tǒng)

在 TypeScript 中實(shí)現(xiàn)一個(gè)類型安全的路由系統(tǒng),可以通過 類型推導(dǎo)類型約束 來確保路由路徑、參數(shù)、查詢參數(shù)和組件類型之間的強(qiáng)一致性。以下是實(shí)現(xiàn)一個(gè)類型安全路由系統(tǒng)的完整方案:

目標(biāo)

  • 路由路徑類型安全(路徑錯(cuò)誤編譯時(shí)報(bào)錯(cuò))
  • 路由參數(shù)類型安全(路徑參數(shù)類型正確)
  • 查詢參數(shù)類型安全(查詢參數(shù)類型正確)
  • 路由組件類型安全(路由組件類型正確)
  • 支持嵌套路由

1. 定義路由類型結(jié)構(gòu)

我們使用一個(gè) RouteConfig 類型來定義路由結(jié)構(gòu),支持嵌套和參數(shù)。

type RouteConfig<T extends string> = {
  path: T;
  component: React.ComponentType<any>;
  children?: RouteConfig<any>[];
  params?: Record<string, string>; // 可選參數(shù)類型
  query?: Record<string, string>; // 查詢參數(shù)類型
};

但更推薦使用 泛型 + 映射類型 來實(shí)現(xiàn)類型安全。

2. 使用infer和Extract實(shí)現(xiàn)路徑參數(shù)類型推導(dǎo)

我們使用 infer 來從路徑字符串中提取參數(shù)類型。

// 從路徑字符串中提取參數(shù)類型
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>; // 參數(shù)類型
  query?: Record<string, string>; // 查詢參數(shù)類型
};

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 強(qiáng)制類型推導(dǎo)為字面量類型,防止類型丟失。

5. 實(shí)現(xiàn)類型安全的useNavigate和useLocation

useNavigate類型安全

type NavigateOptions<T extends string> = {
  to: T;
  query?: Record<string, string>;
};

function useNavigate() {
  const navigate = useNavigate(); // 假設(shè)使用 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;

  // 提取路徑參數(shù)
  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>);

  // 查詢參數(shù)
  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,可以使用 useParamsuseSearchParams 并結(jié)合類型推導(dǎo)。

function UserDetail() {
  const { id } = useParams<{ id: string }>();
  const [searchParams] = useSearchParams();

  const postId = searchParams.get('postId');

  return <div>User {id} Post {postId}</div>;
}

useParamsuseSearchParams 本身支持類型推導(dǎo),但需要手動(dòng)指定類型。

9. 高級(jí):使用zod+TypeScript實(shí)現(xiàn)查詢參數(shù)驗(yà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. 總結(jié):類型安全路由系統(tǒng)的關(guān)鍵點(diǎn)

功能實(shí)現(xiàn)方式
路徑類型安全使用 infer 提取路徑參數(shù)
參數(shù)類型安全params 字段顯式定義類型
查詢參數(shù)類型安全query 字段定義類型,配合 zod 驗(yàn)證
組件類型安全component 類型為 React.ComponentType<any>
路由跳轉(zhuǎn)安全useNavigate 類型約束 to 路徑
嵌套路由使用 children 字段遞歸定義

最終建議

  • 使用 React Router v6Next.js App Router(推薦)
  • 使用 zod 驗(yàn)證查詢參數(shù)
  • 使用 as const 固定路由配置類型
  • 使用 infer 提取路徑參數(shù)類型
  • 使用 useNavigateuseLocation 封裝類型安全接口

示例項(xiàng)目結(jié)構(gòu)

src/
  routes/
    index.ts
    user.ts
  components/
    Home.tsx
    UserDetail.tsx
  hooks/
    useNavigate.ts
    useLocation.ts

通過以上方式,你可以構(gòu)建一個(gè) 完全類型安全 的路由系統(tǒng),避免運(yùn)行時(shí)錯(cuò)誤,提升開發(fā)體驗(yàn)。

到此這篇關(guān)于TypeScript中如何實(shí)現(xiàn)類型安全的路由系統(tǒng)的文章就介紹到這了,更多相關(guān)TypeScript實(shí)現(xiàn)路由系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Js 本頁面?zhèn)髦祵?shí)現(xiàn)代碼

    Js 本頁面?zhèn)髦祵?shí)現(xiàn)代碼

    記得以前在學(xué)校的時(shí)候,例如要修改信息,需要要修改的部分的值顯示出來,都是先把數(shù)據(jù)傳到后臺(tái),然后再在前臺(tái)顯示的,想想真夠笨的,這個(gè)可以在客戶端就實(shí)現(xiàn)的,何必要傳到后臺(tái)呢
    2009-05-05
  • javascript eval和JSON之間的聯(lián)系

    javascript eval和JSON之間的聯(lián)系

    本文著重解釋eval函數(shù)和JSON數(shù)據(jù)格式之間的聯(lián)系以及一些細(xì)節(jié)上的問題。
    2009-12-12
  • JS庫之Highlight.js的用法詳解

    JS庫之Highlight.js的用法詳解

    highlight.js是一款輕量級(jí)的Web代碼語法高亮庫。下面通過實(shí)例代碼給大家分享JS庫之Highlight.js的用法詳解,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧
    2017-09-09
  • JS關(guān)于刷新頁面的相關(guān)總結(jié)

    JS關(guān)于刷新頁面的相關(guān)總結(jié)

    在本篇內(nèi)容中我們給大家整理了關(guān)于JS刷新頁面的所有相關(guān)知識(shí)點(diǎn)以及整理了相關(guān)的技術(shù)文章,大家可以收藏本頁面繼續(xù)深入學(xué)習(xí)。
    2018-05-05
  • jquery div模態(tài)窗口的簡(jiǎn)單實(shí)例

    jquery div模態(tài)窗口的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)硪黄猨query div模態(tài)窗口的簡(jiǎn)單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-05-05
  • 用JS實(shí)現(xiàn)HTML標(biāo)簽替換效果

    用JS實(shí)現(xiàn)HTML標(biāo)簽替換效果

    用JS實(shí)現(xiàn)HTML標(biāo)簽替換效果...
    2007-06-06
  • 微信小程序單選框自定義賦值

    微信小程序單選框自定義賦值

    這篇文章主要介紹了微信小程序單選框如何自定義賦值,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • HTML DOM Viewer

    HTML DOM Viewer

    HTML DOM Viewer...
    2006-09-09
  • JavaScript簡(jiǎn)單實(shí)現(xiàn)鼠標(biāo)移動(dòng)切換圖片的方法

    JavaScript簡(jiǎn)單實(shí)現(xiàn)鼠標(biāo)移動(dòng)切換圖片的方法

    這篇文章主要介紹了JavaScript簡(jiǎn)單實(shí)現(xiàn)鼠標(biāo)移動(dòng)切換圖片的方法,涉及JavaScript針對(duì)鼠標(biāo)事件的響應(yīng)及頁面元素的動(dòng)態(tài)變換技巧,需要的朋友可以參考下
    2016-02-02
  • javascript css styleFloat和cssFloat

    javascript css styleFloat和cssFloat

    在寫js操作css的過程中發(fā)現(xiàn)float屬性在IE和firefox下對(duì)應(yīng)的js腳本是不一樣的,IE下對(duì)應(yīng)得是 styleFloat,firefox,chorme,safari下對(duì)應(yīng)的是cssFloat,可用in運(yùn)算符去檢測(cè)style是否包含此屬性。
    2010-03-03

最新評(píng)論