Bluebird/Typescript报错:this上下文无法分配给方法的this类型
问题根因
你遇到的TS报错本质是联合类型的方法上下文校验规则导致的:
你定义的sequence数组的元素是两个函数类型的联合:(this: Template) => Promise<number> | (this: Template) => number。当你用fn.call(instance)调用时,TS会尝试将联合类型的所有成员都匹配上下文校验规则,由于返回值不统一,就触发了类型不兼容的报错。
你观察到的几个现象也都是这个逻辑导致的:
- 方法拆出实例后丢失
this:类的普通方法本身不绑定this,单独调用时this指向运行时上下文,而非原实例 methodA改为同步后无报错:两个方法返回值统一为number,联合类型的校验规则匹配- 移除
return后无报错:两个方法返回值统一为void,联合类型校验通过 - 用
bind调用无报错:bind会固定函数的this指向,TS不需要再校验call传入的this参数,不会触发联合类型的上下文匹配校验
问题1 调整代码过TS校验的方案
方案1:给sequence显式声明类型(推荐,保留完整类型校验)
直接告诉TS数组内的方法都是接收Template作为this、返回值为同步/异步number即可:
const sequence: Array<(this: Template) => number | Promise<number>> = [instance.methodA, instance.methodB];
后续fn.call(instance)调用的逻辑完全不需要改,就能通过TS校验。
方案2:提前绑定this
定义sequence的时候就把方法的this绑定到实例,后续调用不需要手动传上下文:
const sequence = [instance.methodA.bind(instance), instance.methodB.bind(instance)]; // 调用时直接执行即可 const result = fn();
方案3:调用时加类型断言(不推荐,丢失部分类型校验)
如果你不想改数组定义,也可以在调用时告诉TS你确认this上下文正确:
const result = fn.call(instance as Template);
问题2 更简便的顺序调用方案
方案1:原生for循环实现串行(无需依赖bluebird,最简洁)
如果你的方法列表是动态生成的,用for await循环自动处理同步/异步返回值,同时提前绑定this:
// 提前绑定this,或者直接包装为箭头函数天然保留this const sequence = [ () => instance.methodA(), () => instance.methodB() ]; (async function main() { for (const fn of sequence) { const result = await fn(); console.log({ result }); } })();
如果方法列表是固定的,直接按顺序调用就行,完全不需要额外工具:
(async function main() { console.log({ result: await instance.methodA() }); console.log({ result: instance.methodB() }); })();
方案2:bluebird调用简化版
如果一定要用bluebird.each,直接把方法包装为箭头函数,不用处理this绑定:
const sequence = [() => instance.methodA(), () => instance.methodB()]; await bluebird.each(sequence, async (fn) => { const result = await fn(); console.log({ result }); });
内容的提问来源于stack exchange,提问作者1252748
相关产品推荐
相关产品推荐

