TypeScript中调用call方法时extends keyof约束变为never问题
问题原因
TypeScript的泛型参数推导是从左到右、从调用参数到返回值顺序执行的,对于带this参数的函数,当你使用Function.prototype.call调用时,泛型的推导顺序出现了冲突:
withLoading的泛型T是绑定到函数自身的this参数的,而通过call调用时,TypeScript无法优先从call的第一个thisArg参数反向推导上层函数的T泛型- 泛型
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
相关产品推荐
相关产品推荐

