TypeScript路由构建函数无占位符时参数设为可选的实现方法
路由构建函数类型校验实现方案
功能要求
实现一个带类型校验的路由构建函数,满足以下规则:
- 仅支持传入预定义的合法路由
- 路由包含占位符时,必须传入键名、类型完全匹配的参数对象
- 路由无占位符时,不可传入参数
预期类型校验效果如下:
type Route = '/no-placeholders' | '/path/:p1/:p2' buildUrl('/unknown-route') // 报错:路由不存在 buildUrl('/no-placeholders', {}) // 报错:无需传参却收到多余参数 buildUrl('/no-placeholders') // 校验通过 buildUrl('/path/:p1/:p2') // 报错:缺少必填参数 buildUrl('/path/:p1/:p2', { foo: '' }) // 报错:参数与路由占位符不匹配 buildUrl('/path/:p1/:p2', { p1: 'foo', p2: 'bar' }) // 校验通过
原有实现问题
初始实现尝试通过never类型重载处理无参场景,但未生效,代码如下:
type PathParams<Path extends string> = Path extends `:${infer Param}/${infer Rest}` ? { [k in Param | keyof PathParams<Rest>]: string } : Path extends `:${infer Param}` ? { [k in Param]: string } : Path extends `${infer _Prefix}:${infer Rest}` ? { [k in keyof PathParams<`:${Rest}`>]: string } : never; type Route = '/no-placeholders' | '/path/:p1/:p2' function buildUrl<R extends Route>(route: R, params: never): string; function buildUrl<R extends Route>(route: R, params: PathParams<R>): string; function buildUrl(route: any, params: any) { // 路由参数替换逻辑省略 return route }
存在的问题:不管路由是否包含占位符,函数始终要求传入第二个参数,无参路由的可选参数规则未生效。
最终解决方案
通过函数重载分别处理有参、无参路由场景即可:
type PathParams<Path extends string> = Path extends `:${infer Param}/${infer Rest}` ? { [k in Param | keyof PathParams<Rest>]: string } : Path extends `:${infer Param}` ? { [k in Param]: string } : Path extends `${infer _Prefix}:${infer Rest}` ? { [k in keyof PathParams<`:${Rest}`>]: string } : never; // 拆分路由类型为无参、有参两类 type RouteWithoutParams = '/no-placeholders' type RouteWithParams = '/path/:p1/:p2' type Route = RouteWithoutParams | RouteWithParams // 无参路由重载:仅需要传路由参数 function buildUrl<R extends RouteWithoutParams>(route: R): string; // 有参路由重载:必须同时传入匹配的参数对象 function buildUrl<R extends Route>(route: R, params: PathParams<R>): string; // 实现层将第二个参数设为可选,兼容两个重载分支 function buildUrl<R extends string>(route: R, params?: PathParams<R>) { // 路由参数替换逻辑省略 return route }
内容的提问来源于stack exchange,提问作者raxell
相关产品推荐
相关产品推荐

