[英]React router 6+ : how to strongly type the params option in route loader?
有路由器
export const router = createBrowserRouter([
{
path: '/todos/:todoId',
element: <Todo />,
loader: todoLoader,
}
]);
有装载机
export const loader: LoaderFunction = async ({ params }) => {
return await fetchData(params.todoId);
};
如何根据路径键入参数?
等待路径中指定参数的突出显示。
更新:感谢@DrewReese @LindaPaiste 来到以下解决方案。
const PathNames = {
todoDetail: '/todos/:idTodo',
} as const;
interface Args extends ActionFunctionArgs {
params: Params<ParamParseKey<typeof PathNames.todoDetail>>;
}
export const loader: LoaderFunction = async ({ params }:Args) => {
return await fetchData(params.todoId);
};
declare type _PathParam<Path extends string> = Path extends `${infer L}/${infer R}`? _PathParam<L> | _PathParam<R>: Path extends `:${infer Param}`? Param extends `${infer Optional}?`? Optional: Param: never; /** * Examples: * "/a/b/*" -> "*" * ":a" -> "a" * "/a/:b" -> "b" * "/a/blahblahblah:b" -> "b" * "/:a/:b" -> "a" | "b" * "/:a/b/:c/*" -> "a" | "c" | "*" */ declare type PathParam<Path extends string> = Path extends "*"? "*": Path extends `${infer Rest}/*`? "*" | _PathParam<Rest>: _PathParam<Path>; export declare type ParamParseKey<Segment extends string> = [ PathParam<Segment> ] extends [never]? string: PathParam<Segment>; /** * The parameters that were parsed from the URL path. */ export declare type Params<Key extends string = string> = { readonly [key in Key]: string | undefined; };
声明路径的映射/对象(键-值),您可以使用 RRD 的Params
和ParamParseKey
实用程序类型来提取路由路径参数(方法归功于 LindaPaiste 和 Qvazi )。
const Paths = {
todoDetail: "/todos/:idTodo",
} as const;
interface TodoLoaderArgs extends ActionFunctionArgs {
params: Params<ParamParseKey<typeof Paths.todoDetail>>;
}
const todoLoader: LoaderFunction = async ({ params }: TodoLoaderArgs) => {
return await fetchData(params.idTodo);
};
const router = createBrowserRouter([
{
path: Paths.todoDetail,
element: <Todo />,
loader: todoLoader as LoaderFunction
},
]);
但是, fetchData
function 需要一个string
类型,因此这里存在不兼容性,因为params.idTodo
被键入为string | undefined
string | undefined
。 它通过在访问之前进行条件检查来修复
const todoLoader: LoaderFunction = async ({ params }: TodoLoaderArgs) => {
return params.idTodo ? await fetchData(params.idTodo) : null;
};
或断言它是非空的,例如fetchData(params.idTodo!)
或者您可以提供后备,例如fetchData(params.idTodo?? "")
。 也许回退可以是数据获取的一些默认查询参数值。
const todoLoader: LoaderFunction = async ({ params }: TodoLoaderArgs) => {
return await fetchData(params.idTodo ?? "");
};
这是一个有点迂回的方法,但这似乎是正确输入的,并且在运行的 codesandbox 中工作,虽然可能有点“hackish”(我的 Typescript foo 不是很好)。 要点是您需要覆盖加载程序 function args
参数,以便您可以覆盖params
属性以包含要在加载程序中访问的路径参数。
要覆盖的加载程序定义:
/** * The parameters that were parsed from the URL path. */ export declare type Params<Key extends string = string> = { readonly [key in Key]: string | undefined; }; /** * @private * Arguments passed to route loader/action functions. Same for now but we keep * this as a private implementation detail in case they diverge in the future. */ interface DataFunctionArgs { request: Request; params: Params; context?: any; } /** * Arguments passed to loader functions */ export interface LoaderFunctionArgs extends DataFunctionArgs { } /** * Route loader function signature */ export interface LoaderFunction { (args: LoaderFunctionArgs): Promise<Response> | Response | Promise<any> | any; }
新的接口声明和用法:
import {
RouterProvider,
createBrowserRouter,
Navigate,
useLoaderData,
LoaderFunction,
LoaderFunctionArgs
} from "react-router-dom";
interface TodoLoaderFunctionArgs extends Omit<LoaderFunctionArgs, "params"> {
params: {
todoId: string;
};
}
interface TodoLoaderFunction extends Omit<LoaderFunction, "args"> {
(args: TodoLoaderFunctionArgs):
| Promise<Response>
| Response
| Promise<any>
| any;
}
const todoLoader: TodoLoaderFunction = async ({ params }) => {
return await fetchData(params.todoId);
};
const router = createBrowserRouter([
{
path: "/todos/:todoId",
element: <Todo />,
loader: todoLoader as LoaderFunction
},
]);
另一种可能更简单的方法是简单地重铸params
道具。
interface Params {
todoId: string
}
const todoLoader: LoaderFunction = async ({ params }) => {
const typedParams = params as unknown as Params;
return await fetchData(typedParams.todoId);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.