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

TypeScript泛型推断问题:createRoute的props回调参数类型异常

TypeScript createRoute函数泛型类型问题解决

问题背景

我正在为TypeScript函数createRoute定义泛型:

export function createRoute<
  const TOptions,
  const TComponent extends Component
>(options: TOptions & CreateRouteOptions & WithComponent<TComponent, TOptions>): Route<TOptions> { ... }

相关类型定义如下:

  • CreateRouteOptions是路由基础属性类型:
export type CreateRouteOptions = {
  name: string,
  path: string,
  query: string,
}
  • WithComponent包含组件及props回调上下文:
export type WithComponent<
  TComponent extends Component = Component,
  TOptions = unknown
> = {
  component: TComponent,
  props?: (route: TOptions) => ComponentProps<TComponent>,
}

createRoute仅接收一个对象参数,TOptions本应匹配CreateRouteOptions,但如果把泛型设为const TOptions extends CreateRouteOptions会破坏WithComponent的类型推导。目前大部分功能正常,但props回调的route参数类型是unknown,而非预期的具体字面量类型(比如{ name: 'foo', path: '/', query: '' }),我搞不懂TypeScript是怎么推导TOptions类型的。

示例代码:

const myRoute = createRoute({
  name: 'foo',
  path: '/',
  query: '',
  component: SomeComponent,
  props: (route) => { ... }
  //        ^? 预期类型:{ name: 'foo', path: '/', query: '' } 实际类型:unknown
})

完整可运行示例:

type Component = { template: string, script: string, props: Record<string, any> }
type ComponentProps<T> = T extends { props: infer TProps extends Record<string, any> } ? TProps : {}
const SomeComponent = {
    template: 'something',
    script: '',
    props: {
        foo: true,
        bar: 123
    }
} satisfies Component

type Route<T> = T & {id: number}

type CreateRouteOptions = {
  name: string,
  path: string,
  query: string,
}

export type WithComponent<
  TComponent,
  TOptions
> = {
  component: TComponent,
  props?: (route: TOptions) => ComponentProps<TComponent>,
}

function createRoute<
  const TOptions,
  const TComponent
>(options: TOptions & CreateRouteOptions & WithComponent<TComponent, TOptions>): Route<TOptions> {
    throw 'not implemented'
}

const myRoute = createRoute({
  name: 'foo',
  path: '/',
  query: '',
  component: SomeComponent,
  props: (route) => ({ foo: true, bar: 14 })
  //        ^? 预期类型:{ name: 'foo', path: '/', query: '' } 实际类型:unknown
})

问题分析

当前泛型约束的核心问题是:TOptions和WithComponent<TComponent, TOptions>形成了循环依赖,TypeScript无法在推导TOptions的同时解析props回调的参数类型,只能默认设为unknown。另外,直接给TOptions加extends CreateRouteOptions会让TypeScript将其推断为CreateRouteOptions基类型,而非传入的具体字面量值。

解决方案

调整泛型结构,先让TypeScript捕获TOptions的完整字面量类型,再确保它符合CreateRouteOptions约束,同时关联WithComponent的类型推导:

type CreateRouteProps<TOptions extends CreateRouteOptions, TComponent> = 
  TOptions & WithComponent<TComponent, TOptions>;

function createRoute<
  const TOptions extends CreateRouteOptions,
  const TComponent extends Component
>(options: CreateRouteProps<TOptions, TComponent>): Route<TOptions> {
    throw 'not implemented'
}

通过拆分类型组合,让TOptions先被推断为具体的字面量类型,再代入WithComponent中,这样props回调的route参数就能正确关联到TOptions的具体值。

验证效果

修改后,示例中的route参数类型会被正确推断为{ name: 'foo', path: '/', query: '' },完全符合预期。

内容的提问来源于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 02:08:13