safe-routes

用於操作 React Router 應用程式中內部連結的型別安全輔助工具。

[!note] remix-routes 已重新命名為 safe-routes。如果您正在尋找 remix-routes 的文件,請參考這裡

如果您要從 remix-routes 升級,請參考升級指南

重點特色

安裝

$ npm add safe-routes

設定

safeRoutes 外掛程式添加到您的 vite.config.ts

import { defineConfig } from "vite";
import { reactRouter } from "@react-router/dev/vite";
import { safeRoutes } from 'safe-routes/vite';

export default defineConfig({
  plugins: [
    reactRouter(),
    safeRoutes(),
  ],
});

支援的設定選項

  • strict: boolean
  • outDir: string

safe-routes typegen 新增到 typecheck 腳本

- "typecheck": "react-router typegen && tsc --build --noEmit"
+ "typecheck": "react-router typegen && safe-routes typegen && tsc --build --noEmit"

用法

型別化的 URL 生成

import { redirect } from 'react-router';
import { $path } from 'safe-routes'; // <-- Import magical $path helper from safe-routes.

export const action = async ({ request }) => {
  let formData = await request.formData();
  const post = await createPost(formData);

  return redirect($path('/posts/:id', { id: post.id })); // <-- It's type safe.
};

附加查詢字串

import { $path } from 'safe-routes';

$path('/posts/:id', { id: 6 }, { version: 18 }); // => /posts/6?version=18
$path('/posts', { limit: 10 }); // => /posts?limit=10
// You can pass any URLSearchParams init as param
$path('/posts/delete', [['id', 1], ['id', 2]]); // => /posts/delete?id=1&id=2

型別化的查詢字串

藉由在路由檔案中匯出一個名為 SearchParams 的型別來定義查詢字串的型別

// app/routes/posts.tsx

export type SearchParams = {
  view: 'list' | 'grid',
  sort?: 'date' | 'views',
  page?: number,
}
import { $path } from 'safe-routes';

// The query string is type-safe.
$path('/posts', { view: 'list', sort: 'date', page: 1 });

您可以將此功能與 zodremix-params-helper 結合使用,以新增執行階段參數檢查

import { z } from "zod";
import { getSearchParams } from "remix-params-helper";

const SearchParamsSchema = z.object({
  view: z.enum(["list", "grid"]),
  sort: z.enum(["price", "size"]).optional(),
  page: z.number().int().optional(),
})

export type SearchParams = z.infer<typeof SearchParamsSchema>;

export const loader = async (request) => {
  const result = getSearchParams(request, SearchParamsSchema)
  if (!result.success) {
    return json(result.errors, { status: 400 })
  }
  const { view, sort, page } = result.data;
}

型別化的路由 ID

safe-routes 會匯出 RouteId 型別定義,其中包含您儲存庫中所有有效路由 ID 的列表,並具有一個輔助函式 $routeId,可告訴 TypeScript 將給定的字串限制為有效的 RouteId 值之一。

import type { RouteId } from 'safe-routes';
import type { loader as postsLoader } from './_layout.tsx';
import { useRouteLoaderData } from 'react-router';
import { $routeId } from 'safe-routes';

export default function Post() {
  const postList = useRouteLoaderData<typeof postsLoader>($routeId('routes/posts/_layout'));
}

支援 basename

開箱即用支援 Basename。如果您在 vite.config.tsreact-router.config.ts 中設定了 basename,safe-routes 將會自動將 basename 前置到生成的 URL 中。

// react-router.config.ts
import type { Config } from "@react-router/dev/config";

export default {
  basename: "/blog",
} satisfies Config;
import { $path } from 'safe-routes';

$path('/posts/:id', { id: 6 }); // => /blog/posts/6

授權條款

MIT