You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何推断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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:13:18