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

TypeScript中调用call方法时extends keyof约束变为never问题

问题原因

TypeScript的泛型参数推导是从左到右、从调用参数到返回值顺序执行的,对于带this参数的函数,当你使用Function.prototype.call调用时,泛型的推导顺序出现了冲突:

  1. withLoading的泛型T是绑定到函数自身的this参数的,而通过call调用时,TypeScript无法优先从call的第一个thisArg参数反向推导上层函数的T泛型
  2. 泛型T没有被成功推导时默认会被当做空对象{}处理,keyof {}的计算结果就是never,自然在P extends keyof T的约束下,loadingName的类型就变成了never

解决方法

方法1:调用时手动指定泛型参数

直接在调用时显式传入T的类型,跳过自动推导:

// 假设你绑定的this上下文是MyComponent类型
withLoading.call<MyComponent>(this, 'loading', async () => {
  // 业务逻辑
})

方法2:修改withLoading定义,把this参数改为普通参数

不需要依赖TypeScript的this参数推导,把上下文对象作为第一个普通参数传入,从根源避免推导问题:

function withLoading<T, P extends keyof T>(ctx: T, loadingName: P, before: () => Promise<any>): Promise<void> {
  // 原有实现里的this全部替换为ctx即可
}
// 调用时直接传上下文,不需要用call,类型能正常推导
withLoading(this, 'loading', async () => {
  // 业务逻辑
})

方法3:为withLoading重载call方法的类型

如果一定要保留this参数的写法,可以给withLoading补充call方法的类型声明:

interface WithLoading {
  <T, P extends keyof T>(this: T, loadingName: P, before: () => Promise<any>): Promise<void>
  // 重载call的类型,建立thisArg和泛型T的关联
  call<T, P extends keyof T>(this: Function, thisArg: T, loadingName: P, before: () => Promise<any>): Promise<void>
}

const withLoading = function<T, P extends keyof T>(this: T, loadingName: P, before: () => Promise<any>): Promise<void> {
  // 原有实现
} as WithLoading

修改后调用withLoading.call时就能从第一个thisArg参数正确推导T的类型,进而得到loadingName的正确类型约束。

内容的提问来源于stack exchange,提问作者Yue JIN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:18:03