如何从树形IRoute结构推导所有路径的字符串联合类型?
问题
我定义了表示Web应用路由的TypeScript接口:
interface IRoute { readonly path: string; readonly children?: IRoute[]; }
给定该类型的示例对象:
const routes: IRoute = { path: '', children: [ { path: '/dashboard', }, { path: '/settings', children: [ { path: '/notifications' }, { path: '/profile', children: [ { path: '/picture' }, ] } ] } ] };
我希望生成包含所有可能路径的联合类型,比如:
type AllRoutes = | '/' | '/dashboard' | '/settings' | '/settings/notifications' | '/settings/profile' | '/settings/profile/picture'
请问是否可以从上述IRoute对象推导出这类全路径联合类型?
解决方案
可以实现,但首先需要调整routes的定义,让TypeScript保留其字面量类型信息(原定义中routes: IRoute会丢失具体的路径字符串和子路由结构细节)。
步骤1:保留路由对象的字面量类型
用as const断言锁定路由对象的字面量类型,避免TypeScript将其宽泛化为IRoute:
const routes = { path: '', children: [ { path: '/dashboard', }, { path: '/settings', children: [ { path: '/notifications' }, { path: '/profile', children: [ { path: '/picture' }, ] } ] } ] } as const;
步骤2:编写递归类型工具拼接路径
定义两个递归条件类型,分别处理单条路由的路径生成和子路由的路径拼接:
// 处理单个路由及其子路由的完整路径生成 type BuildRoutePaths<T extends { path: string; children?: readonly any[] }> = T['path'] extends '' ? '/' | BuildChildPaths<T['children']> : T['path'] | BuildChildPaths<T['children'], T['path']>; // 遍历子路由并拼接父路径 type BuildChildPaths< T extends readonly any[] | undefined, ParentPath extends string = '' > = T extends readonly (infer U)[] ? U extends { path: string; children?: readonly any[] } ? `${ParentPath}${U['path']}` | BuildChildPaths<U['children'], `${ParentPath}${U['path']}`> : never : never; // 生成最终的全路径联合类型 type AllRoutes = BuildRoutePaths<typeof routes>;
验证结果
此时AllRoutes会被TypeScript自动推导为:
type AllRoutes = "/" | "/dashboard" | "/settings" | "/settings/notifications" | "/settings/profile" | "/settings/profile/picture"
核心逻辑是利用TypeScript的递归条件类型和模板字面量类型,结合as const保留的精确字面量信息,自动拼接出所有层级的完整路由路径。
内容的提问来源于stack exchange,提问作者Krimson
相关产品推荐
相关产品推荐

