TypeScript路由函数参数推断与Plugin类型校验报错问题
路由参数推断与Plugin类型校验问题解决
问题
需要实现一个router函数,能够从传入的路径中推断路由参数,并校验plugin的函数结构,但当前代码运行时出现类型错误。
现有代码
interface RouteConfig<Path extends string = string> { hash?: string; name: string; path: Path; plugins?: Array<RouterPlugin<Path>>; search?: string; } type Route<Path extends string> = RouteConfig<Path> & { plugins: Array<RouterPlugin<Path>>; }; interface RouteContext<Params = { [key: string]: string | undefined }, Query = Record<string, string>> { name: string; params: Params; query: Query; url: URL; } type RouterPlugin<Path extends string> = (context: RouteContext<PathParams<Path>>) => void | Promise<void>; type PathParams<Path extends string> = string extends Path ? Record<string, string | undefined> : // eslint-disable-next-line @typescript-eslint/no-unused-vars Path extends `${infer _Start}:${infer Param}/${infer Rest}` ? { [K in Param | keyof PathParams<Rest>]: string } : // eslint-disable-next-line @typescript-eslint/no-unused-vars Path extends `${infer _Start}:${infer Param}` ? { [K in Param]: string } : Record<string, unknown>; function createRouter<T extends RouteConfig>(config: T[]) { // } const router = createRouter([ { name: 'task', path: '/tasks/:id', plugins: [(ctx: { params: { id: string }}) => {}], // 此处报错 }, ]);
错误信息
Property 'id' is missing in type 'Record<string, string | undefined>' but required in type '{ id: string; }'
解决方案
核心问题
createRouter的泛型约束T extends RouteConfig会将所有路由项的Path统一解析为string类型(因RouteConfig默认泛型为string),导致PathParams<Path>触发兜底分支,返回Record<string, string | undefined>,与手动指定的{ params: { id: string } }类型不匹配。
修改方案
调整createRouter的泛型定义,让TypeScript保留每个路由项的具体Path字面量类型:
function createRouter<T extends readonly RouteConfig[]>(config: T) { return config as { [K in keyof T]: T[K] extends RouteConfig<infer P> ? Route<P> : never; }; }
同时,删除plugins中手动指定的ctx类型,TypeScript会自动根据path推断正确的RouteContext结构:
const router = createRouter([ { name: 'task', path: '/tasks/:id', plugins: [(ctx) => { // ctx.params.id 会被正确推断为 string 类型 console.log(ctx.params.id); }], }, ]);
原理说明
修改后的泛型会逐个解析数组中每个路由项的Path类型,触发PathParams的条件类型分支,精准推断出路径中的参数结构,从而让RouterPlugin的上下文类型与路径参数完全匹配。
内容的提问来源于stack exchange,提问作者Andy Jessop
相关产品推荐
相关产品推荐

