为何推断Router泛型第二个参数会受第一个参数推断的影响?
Vue路由类型提取问题及两种修复方案解析
类型定义代码
import { Plugin } from 'vue' type Route = { name: string, path: string, } type Options = Partial<{ rejections: Record<string, unknown> }> type Router<TRoutes extends Route[], TOptions extends Options = Options> = { routes: TRoutes } & Plugin function createRouter< const TRoutes extends Route[], const TOptions extends Options >(routes: TRoutes, options: TOptions): Router<TRoutes, TOptions> { return { install: () => {}, routes } } const myRouter = createRouter([ { name: 'home', path: '/' } ], { rejections: { AuthNeeded: 1 } }) interface Register { router: typeof myRouter }
路由类型提取示例
通过Register接口可以成功提取路由类型:
type RegisteredRoutes = Register extends { router: Router<infer TRoutes> } ? TRoutes : []
问题场景
但提取options中rejections的键类型时,结果不符合预期:
type RegisteredRejections = Register extends { router: Router<Route[], infer TOptions> } ? keyof TOptions['rejections'] : never
期望RegisteredRejections的类型为'AuthNeeded',但实际得到的是泛型string。
两种修复方案及原理
方案1:同时推断路由和选项参数
修改类型提取逻辑,同时对TRoutes和TOptions进行推断:
type RegisteredRejections = Register extends { router: Router<infer TRoutes, infer TOptions> } ? keyof TOptions['rejections'] : never
原理:仅指定第二个泛型参数推断时,TypeScript会优先使用Router中TOptions的默认值Options进行匹配,而非从myRouter的具体类型中提取精确值。同时推断两个泛型参数时,TypeScript会完整匹配Router的实例类型,从而正确提取到包含'AuthNeeded'的键类型。
方案2:移除Router类型中的& Plugin交叉类型
修改Router的类型定义,去掉与Plugin的交叉:
type Router<TRoutes extends Route[], TOptions extends Options = Options> = { routes: TRoutes }
原理:Vue的Plugin类型包含install方法,与自定义Router交叉后,会降低TypeScript的泛型推断精度,使其优先使用泛型参数的默认约束而非实例的具体类型。移除交叉类型后,Router结构更简单,TypeScript能精准推断出TOptions的具体类型。
补充更新
将代码迁移到纯TypeScript环境后,推断结果变为never,这是因为纯TS环境中Vue的Plugin类型定义存在差异,导致泛型推断逻辑变化,需要调整推断方式适配环境。
内容的提问来源于stack exchange,提问作者stackoverfloweth
相关产品推荐
相关产品推荐

