TypeScript递归提取嵌套路由路径类型的实现问题求助
如何在TypeScript中递归提取嵌套路由的所有路径类型
问题描述
我正尝试在TypeScript中构建一个递归类型,用于从给定的路由配置中解析所有可能的路由路径(包括嵌套路径),但遇到了类型约束与推断的问题。
已通过TypedRoute接口和createRoute函数定义了路由:
interface TypedRoute< Path extends string, QueryParams extends Record<string, string> = {} > { path: Path; queryParams?: QueryParams; children?: TypedRoute<any, any>[]; } function createRoute< Path extends string, QueryParams extends Record<string, string> = {} >(config: TypedRoute<Path, QueryParams>) { return config; } const routes = [ createRoute({ path: 'results/:id/foo/:bar' }), createRoute({ path: 'home', children: [ createRoute({ path: 'bar', children: [ createRoute({ path: 'baz' }) ] }), ], }), ]
尝试创建ExtractRoutePaths类型以递归提取所有可能路径:
type ExtractRoutePaths<T extends readonly TypedRoute<any, any>[]> = T extends readonly [] ? never : T extends readonly [infer First, ...infer Rest] ? First extends TypedRoute<infer P, any> ? First extends { children: infer C } ? C extends readonly TypedRoute<any, any>[] ? `{P}` | ExtractRoutePaths<C, `${P}/`> | ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never> : `${P}` | ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never> : `${P}` | ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never> : ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never> : never;
预期得到的路径类型为:results/:id/foo/:bar | home | home/bar | home/bar/baz
问题分析
你的代码存在以下几个关键问题:
- 模板字符串语法错误:
{P}应该是${P},这是TypeScript模板字符串类型的正确写法,原写法会被解析为普通字符串而非变量插值。 - 泛型参数不匹配:你定义的
ExtractRoutePaths只有一个泛型参数T,但调用时传入了两个参数(ExtractRoutePaths<C,${P}/>),导致类型不兼容。 - 缺少父路径拼接逻辑:没有传递父路径前缀来拼接子路径,无法生成
home/bar这类嵌套路径。 - 数组遍历逻辑不完善:原类型在处理数组剩余元素时的类型推断冗余,且没有正确处理子路由的递归拼接。
解决方案
我们需要调整泛型结构,增加一个可选的Prefix参数来传递父路径前缀,同时拆分逻辑为处理单个路由和处理路由数组两部分,让递归更清晰:
// 处理单个路由及其子路由的路径提取 type ExtractSingleRoutePaths< Route extends TypedRoute<any, any>, Prefix extends string = '' > = // 拼接当前路由的完整路径 `${Prefix}${Route['path']}` | // 如果有子路由,递归处理子路由,前缀为当前完整路径 + '/' (Route['children'] extends readonly TypedRoute<any, any>[] ? ExtractRoutePaths<Route['children'], `${Prefix}${Route['path']}/`> : never); // 处理路由数组的路径提取 type ExtractRoutePaths< Routes extends readonly TypedRoute<any, any>[], Prefix extends string = '' > = Routes extends readonly [infer First, ...infer Rest] ? First extends TypedRoute<any, any> ? // 提取当前路由的所有路径 + 剩余路由的所有路径 ExtractSingleRoutePaths<First, Prefix> | ExtractRoutePaths<Rest, Prefix> : ExtractRoutePaths<Rest, Prefix> : never;
测试该类型:
type AllRoutePaths = ExtractRoutePaths<typeof routes>; // 类型结果:"results/:id/foo/:bar" | "home" | "home/bar" | "home/bar/baz"
完全符合预期的路径类型。
内容的提问来源于stack exchange,提问作者Js1234
相关产品推荐
相关产品推荐

