TypeScript无法正确推断函数返回类型,求解决方案
解决API调用返回类型不匹配问题
问题场景
现有后端API调用函数loginCreate,定义如下:
loginCreate: (data: AuthenticationRequest, params: RequestParams = {}) => this.request<AuthenticationResponse, IReason[]>({ path: `/login`, method: "POST", body: data, secure: true, type: ContentType.Json, format: "json", ...params, })
该函数位于类库的Api类中,类库导出方式:
import * as AccountApi from "./lib/api.account"; export { AccountApi };
实际应用中通过accountApiStore实例化:
import { AccountApi } from "@central/api"; export default function accountApiStore(authToken?: string) { if (authToken) { return new AccountApi.Api({ baseUrl: process.env.ACCOUNT_HOST, securityWorker: () => ({ headers: { Authorization: `Bearer ${authToken}` } }) }); } else { return new AccountApi.Api({ baseUrl: process.env.ACCOUNT_HOST }); } }
调用代码如下,但signing变量无法获取期望的AccountApi.HttpResponse<AccountApi.AuthenticationResponse, AccountApi.IReason[]>类型:
const signing = await accountApiStore() .login.loginCreate({ username, password, }) .catch((e) => e); if (!signing.ok) { const res = await signing.json(); return json( { errors: { username: res[0]?.message ?? "Invalid username or password" }, }, { status: 401 }, ); }
问题原因
- 链式
catch破坏类型推断:.catch((e) => e)会把Promise的返回类型改为loginCreate返回类型与catch回调返回值类型的联合类型,TypeScript无法确定signing的具体类型,自然无法匹配期望的HttpResponse类型。 accountApiStore未明确返回类型:尽管函数返回的是AccountApi.Api实例,但分支逻辑可能导致TypeScript自动推断出现偏差,打断后续调用的类型链。
解决方案
方案1:改用try/catch结构(推荐)
移除链式catch,用try/catch捕获错误,让signing保留完整的HttpResponse类型:
try { const signing = await accountApiStore().login.loginCreate({ username, password, }); // 此处signing类型为期望的AccountApi.HttpResponse<...> if (!signing.ok) { const res = await signing.json(); return json( { errors: { username: res[0]?.message ?? "Invalid username or password" }, }, { status: 401 }, ); } // 处理请求成功逻辑 } catch (e) { // 处理网络错误、请求超时等异常情况 return json( { errors: { username: "Request failed" } }, { status: 500 }, ); }
方案2:明确accountApiStore的返回类型
给accountApiStore添加明确的返回类型,确保TypeScript能正确推断后续调用的类型:
import { AccountApi } from "@central/api"; export default function accountApiStore(authToken?: string): AccountApi.Api { if (authToken) { return new AccountApi.Api({ baseUrl: process.env.ACCOUNT_HOST, securityWorker: () => ({ headers: { Authorization: `Bearer ${authToken}` } }) }); } else { return new AccountApi.Api({ baseUrl: process.env.ACCOUNT_HOST }); } }
如果坚持使用链式catch,需让catch返回值类型与HttpResponse兼容(不推荐直接用类型断言,会丢失类型安全):
const signing = await accountApiStore() .login.loginCreate({ username, password }) .catch((e): AccountApi.HttpResponse<AccountApi.AuthenticationResponse, AccountApi.IReason[]> => { // 将错误转换为符合HttpResponse结构的对象 return { ok: false, json: async () => [{ message: e.message || "Request failed" }] }; });
内容的提问来源于stack exchange,提问作者Shabbir Hossain
相关产品推荐
相关产品推荐

