如何在Wretch中为Resolver添加TypeScript静态类型?
为Wretch的Resolver添加类型实现API调用类型安全
优化后的类型安全实现方案
针对你遇到的问题,推荐两种更简洁的实现方式,既避免重复调用.json<T>(),又不用手写冗长的类型声明:
方案A:利用TypeScript自动推断的泛型工厂函数
去掉手动声明的返回类型,让TypeScript自动推断插件组合后的类型,代码更简洁且类型安全:
import wretch from "wretch"; import FormDataAddon from "wretch/addons/formData"; import QueryStringAddon from "wretch/addons/queryString"; export function apiTyped<T>() { return wretch("api-url") .errorType("json") .resolve((r) => r.json<T>()) .addon(FormDataAddon) .addon(QueryStringAddon); }
使用方式和之前一致:
export const getUsers = async (): Promise<User[]> => await apiTyped<User[]>().get("/users");
TypeScript会自动推断出返回的Wretch实例类型,无需手动维护复杂的交叉类型。
方案B:为基础API实例创建泛型resolve方法
如果不想每次都创建新的API实例,可以扩展基础实例,添加一个带泛型的resolve方法:
import wretch from "wretch"; import FormDataAddon from "wretch/addons/formData"; import QueryStringAddon from "wretch/addons/queryString"; const baseApi = wretch("api-url") .errorType("json") .addon(FormDataAddon) .addon(QueryStringAddon); export const api = { get<T>(url: string) { return baseApi.get(url).resolve(r => r.json<T>()); }, post<T>(url: string, data: unknown) { return baseApi.post(data, url).resolve(r => r.json<T>()); // 同理可以扩展put、delete等方法 } };
使用方式更直观:
export const getUsers = async (): Promise<User[]> => await api.get<User[]>("/users");
关于你遇到的两种方法的分析
方法1的优缺点
- 优点:实现简单,无需额外封装,完全贴合Wretch的原生用法
- 缺点:每个请求都需要手动调用
.json<T>(),重复代码较多
方法2的优缺点
- 优点:封装后调用更简洁,无需重复写
.json<T>() - 缺点:手动声明返回类型过于冗长,但去掉显式返回类型是完全可行的,TypeScript的自动推断能力足够覆盖插件组合后的类型,不会影响类型安全
无效实现的原因
你尝试的第三种方法之所以报错,是因为:
- 调用
.resolve((r) => r.json())后,Wretch的返回类型被固定为Promise<unknown>,所以直接赋值给Promise<User[]>会出现类型不匹配 - 一旦调用了
.resolve(),Wretch的链式调用就已经结束,后续无法再调用.json<T>(),因为resolve已经处理了响应解析逻辑
关于你的疑问解答
这是Wretch的预期使用方式吗?
是的,Wretch的TypeScript设计就是通过泛型来明确响应类型,和原生fetch的差异在于:
- 原生fetch返回的是
Promise<Response>,你手动将整个函数的返回类型声明为Promise<User[]>,本质是一种类型断言 - Wretch的链式调用会跟踪每一步的类型,所以需要显式指定解析后的类型,避免隐式的类型断言带来的潜在风险
静态类型安全是否属于过度设计?
不属于过度设计。API调用是前端和后端交互的核心环节,静态类型检查能在开发阶段就发现类型不匹配的问题,避免运行时出现解析错误或数据结构异常。当然,你可以根据项目规模选择合适的实现方式:
- 小型项目:可以用方法1快速实现,接受少量重复代码
- 中大型项目:推荐用方案B封装统一的API调用方法,既保证类型安全,又能统一处理请求/响应拦截、错误处理等逻辑
内容的提问来源于stack exchange,提问作者Amr Gaber
相关产品推荐
相关产品推荐

