能否编写递归校验路由值继承父级与本地root的TypeScript类型?
如何用TypeScript类型强制路由路径继承父级/本地root规则?
给定如下路由结构:
const routes = { root: '/', foo: '/foo', // ok bar: { root:'/bar', foo: '/bar/foo', // ok bar: '/bar/:barId',// ok baz: '/baz' // 应该报错 }, } as const;
我们需要编写TypeScript类型,强制所有路由值必须遵循父级路由root属性或当前节点root属性的路径前缀规则,比如上面的baz: '/baz'因为没有继承bar节点的/bar前缀,应该被TypeScript检测为错误。
解决方案
可以通过递归泛型类型实现这一约束,结合satisfies关键字确保类型检查生效的同时,保留原结构的字面量类型:
// 递归路由节点类型,ParentPath为父级路径前缀,默认根路径 type RouteNode<ParentPath extends string = '/'> = { // 当前节点root必须匹配父级路径,根节点允许任意/开头的路径 root: ParentPath extends '/' ? `/${string}` : ParentPath; } & { // 处理非root的其他路由属性 [K in string]: K extends 'root' ? never // 禁止重复定义root属性 : string extends K ? never // 禁止动态字符串键 : // 子属性要么是子路由节点(递归传递当前root作为父路径),要么是符合前缀规则的路径字符串 RouteNode<`${ParentPath extends '/' ? '' : ParentPath}/${string}`> | `${ParentPath extends '/' ? '' : ParentPath}/${string}`; }; // 应用类型约束 const routes = { root: '/', foo: '/foo', // ✅ 符合根路径前缀规则 bar: { root: '/bar', foo: '/bar/foo', // ✅ 符合bar节点的/bar前缀 bar: '/bar/:barId',// ✅ 带参数的路径也符合前缀规则 baz: '/baz' // ❌ 报错:类型"/baz"不符合`/bar/${string}`的前缀要求 }, } as const satisfies RouteNode;
类型说明
- 递归约束:
RouteNode是泛型递归类型,每个子节点会自动继承父节点的路径前缀 - Root属性校验:当前节点的
root必须匹配父级路径,根节点的root允许任意/开头的路径 - 子路径校验:所有非root的路由属性,要么是子路由节点(继续递归约束),要么是字符串路径,且必须以父级路径前缀开头
- 保留字面量类型:使用
as const satisfies RouteNode,既保证类型约束生效,又保留原对象的字面量类型(方便后续路由跳转等场景直接使用)
内容的提问来源于stack exchange,提问作者Matthieu Riegler
相关产品推荐
相关产品推荐

