TypeScript实例方法索引类型错误:动态调用HttpClient方法编译失败问题求助
你的问题核心在于TypeScript无法处理联合类型方法的调用——因为get/post/patch的参数类型(比如GetRequestParams和PutRequestParams)不兼容,TS没法确定你调用的是哪个方法,所以会抛出“此表达式不可调用”的错误;第二个void参数的错误其实是第一个错误的连锁反应,因为TS没法正确推断方法的返回类型。
下面给你两种可行的解决方案:
方案1:类型断言(简洁动态)
既然我们知道ts-mockito的anything()匹配器可以兼容所有方法的参数类型,而且我们返回的success符合HttpResponse的结构,那可以手动给方法做类型断言,告诉TS这个方法的参数和返回类型:
import { HttpResponse } from 'your-http-client-types'; // 确保导入正确的类型 function whenAccountApiRequestSucceeds(httpVerb: 'get' | 'post' | 'patch') { const success = { statusCode: 200, headers: {}, body: account }; // 断言方法为接受任意参数、返回HttpResponse Promise的类型 const requestMethod = httpClient[httpVerb] as (params: unknown) => Promise<HttpResponse<any>>; when(requestMethod(anything())).thenResolve(success); }
这样TS就不会再纠结参数类型不兼容的问题,因为我们明确告诉它这个方法可以接受任何参数(而anything()会被mock框架处理,不需要严格的参数校验),同时返回的Promise类型和success完全匹配,第二个错误也会自动消失。
方案2:类型守卫(类型安全)
如果想要更严格的类型检查,避免类型断言的“绕过”行为,可以用switch做类型守卫,让TS明确知道每个分支调用的是哪个方法:
function whenAccountApiRequestSucceeds(httpVerb: 'get' | 'post' | 'patch') { const success = { statusCode: 200, headers: {}, body: account }; switch (httpVerb) { case 'get': when(httpClient.get(anything())).thenResolve(success); break; case 'post': when(httpClient.post(anything())).thenResolve(success); break; case 'patch': when(httpClient.patch(anything())).thenResolve(success); break; } }
这种写法虽然不是完全“动态”,但比你最后写三个when的方式更简洁,而且TS能100%推断每个方法的类型,不会有编译错误。如果后续要新增方法,只需要在switch里加对应的分支即可。
关于你第三次尝试的Pick错误
你用Pick<keyof HttpClient, 'get' | 'post' | 'patch'>是多余的——keyof HttpClient已经包含了get/post/patch这些字符串字面量,直接用httpVerb: 'get' | 'post' | 'patch'就足够了。Pick的作用是从对象类型中选择属性,不是用来定义索引类型,所以才会抛出lint错误。
内容的提问来源于stack exchange,提问作者Caio Salgado

