告别 TS 报错:优雅扩展 Vue Router 的 RouteMeta
在用 Vue 3 + Vue Router + TypeScript 写后台权限控制时,你是不是也遇到过这种情况:
router.beforeEach((to, from, next) => {
if (to.meta.roles.some(role => role === 'admin')) {
next()
} else {
next('/forbidden')
}
})
结果 TypeScript 却给你来了个下马威:
Property 'some' does not exist on type '{}'.
明明在路由里写了 meta: { roles: ['admin'] }
,为什么 TS 就不认呢?🤔
别急,这其实是因为 Vue Router 默认的类型定义太“保守”了。
1. Vue Router 默认的 RouteMeta
在 Vue Router 源码里,RouteMeta
默认是这样的(简化后):
export interface RouteMeta extends Record<string | number | symbol, unknown> {}
意思就是:它默认是一个空对象 {}
,你可以随便往里面放值,但 TS 并不知道你具体放了啥。
所以当你写 to.meta.roles
时,TS 只知道 meta
是 {}
,自然报错:
Property 'roles' does not exist on type '{}'
2. 正确做法:扩展 RouteMeta 类型
解决办法就是自己告诉 TypeScript:
“嘿,我的 RouteMeta
里有这些字段,帮我记住!”
在项目里新建一个 src/types/router.d.ts
文件:
import 'vue-router'
declare module 'vue-router' {
interface RouteMeta {
title?: string
requiresAuth?: boolean
roles?: string[]
}
}
这里利用了 TypeScript 的 模块声明合并(Declaration Merging) 特性。
这样 TS 就会把你写的字段合并到 Vue Router 原本的 RouteMeta
上。
3. 扩展之后的效果
扩展完成后,RouteMeta
类型变成了:
interface RouteMeta {
title?: string
requiresAuth?: boolean
roles?: string[]
}
这下 to.meta.roles
就能被识别为 string[] | undefined
,自然支持 .some()
方法。
改写后的代码:
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && to.meta.roles?.some(role => role === 'admin')) {
next()
} else {
next('/forbidden')
}
})
不仅不报错,还能享受类型提示。
4. 总结
- 报错原因:Vue Router 默认的
RouteMeta
是个空对象{}
,没有roles
。 - 解决方案:通过
declare module 'vue-router'
扩展RouteMeta
,加上你需要的字段。 - 最终效果:TS 正确识别你的自定义
meta
,类型提示更友好,开发体验更丝滑。
💡 小技巧:
除了 roles
,你还可以在 RouteMeta
里扩展更多字段,比如:
interface RouteMeta {
title?: string
requiresAuth?: boolean
roles?: string[]
icon?: string
keepAlive?: boolean
}