TypeScript中实现返回类型依赖另一泛型参数的HTTP请求函数
正确实现支持多解析类型的泛型HTTP请求函数
你的核心需求是让HTTP函数根据传入的解析类型(text/json/blob),精确返回对应类型的parsedBody,而不是模糊的联合类型。之前的写法问题在于没有建立解析类型和返回类型的精确映射,导致TypeScript无法推断出正确的类型关联。
下面是完整的正确实现方案:
第一步:定义解析类型与返回类型的映射
首先我们需要一个类型映射表,把每种解析方式和对应的返回类型绑定起来:
// 定义解析类型到返回类型的映射 type BodyParserMap = { text: string; json: unknown; blob: Blob; }; // 提取所有支持的解析类型作为联合类型 type BodyParserType = keyof BodyParserMap; // 自定义的HttpResponse类型(假设你之前的定义类似这样) type HttpResponse<T> = Response & { parsedBody?: T; parsedSuccessfully: boolean; };
第二步:实现泛型HTTP函数
我们使用两个泛型参数:
P:指定解析类型(text/json/blob),默认值为jsonT:仅当P为json时生效,用于指定JSON解析后的类型,默认值为unknown
函数会根据P的类型,自动推断parsedBody的类型:
export async function http< P extends BodyParserType = 'json', T = P extends 'json' ? unknown : never >( request: RequestInfo, init?: RequestInit, parserType: P = 'json' as P ): Promise<HttpResponse<P extends 'json' ? T : BodyParserMap[P]>> { const response = await fetch(request, init); const httpResponse: HttpResponse<any> = { ...response, parsedSuccessfully: false, }; try { switch (parserType) { case 'text': httpResponse.parsedBody = await response.text(); break; case 'blob': httpResponse.parsedBody = await response.blob(); break; case 'json': httpResponse.parsedBody = await response.json() as T; break; } httpResponse.parsedSuccessfully = true; } catch (ex) { httpResponse.parsedSuccessfully = false; } return httpResponse as HttpResponse<P extends 'json' ? T : BodyParserMap[P]>; }
第三步:调用示例
现在你可以根据不同的需求调用函数,TypeScript会自动推断出正确的parsedBody类型:
1. 解析为文本(string类型)
http<'text'>('http://localhost/text-endpoint').then((data) => { if (data.ok && data.parsedSuccessfully) { // data.parsedBody 类型为 string console.log(data.parsedBody.toUpperCase()); } });
2. 解析为JSON(指定自定义类型)
interface User { id: number; name: string; } http<'json', User>('http://localhost/user').then((data) => { if (data.ok && data.parsedSuccessfully) { // data.parsedBody 类型为 User console.log(data.parsedBody.name); } }); // 或者省略第一个泛型参数,默认使用json解析 http<User>('http://localhost/user').then((data) => { // 效果同上,data.parsedBody 类型为 User });
3. 解析为Blob
http<'blob'>('http://localhost/image').then((data) => { if (data.ok && data.parsedSuccessfully) { // data.parsedBody 类型为 Blob const imageUrl = URL.createObjectURL(data.parsedBody); } });
为什么之前的写法有问题?
- 第一种写法:直接把
response.text()的结果赋值给parsedBody(类型为T),但string不一定兼容T,所以TypeScript报错。 - 第二种写法:泛型约束
V extends string = 'text' | 'json' | 'blob'没有建立V和返回类型的关联,TypeScript仍然无法推断parsedBody的具体类型。 - 第三种写法:返回
HttpResponse<T | string | Blob>是联合类型,无法精确区分每种解析方式对应的类型,不符合你需要的类型精确性要求。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

