typescript - 如何根据构造函数选项设置方法返回类型?
问题描述
在实现速率限制的get之上开发一个开源抽象。
一切都很好,除了我无法弄清楚如何将返回类型设置为使用构造函数选项提供的 、 、 和post
方法get
(patch
请参阅参考资料)。put
delete
responseType
responseType: options?.responseType ?? "json",
我使用覆盖来使用responseType
方法参数(如果提供)设置返回类型,但我不知道如何为构造函数选项执行此操作。真的可以用这个!
顺便说一句,除了这里的答案,如果您想为该项目做出贡献,请随时向https://github.com/sunknudsen/http提交 PR。
type ResponseType = "buffer" | "json" | "text"
interface HTTPOptions { responseType?: ResponseType }
interface HTTPResponse<T = unknown> { body: T }
class HTTP {
constructor(public options: HTTPOptions) {
this.options.responseType = options.responseType ?? "json"; // Default response type is JSON
}
public get( url: string, options: HTTPOptions & { responseType: "buffer" }): Promise<HTTPResponse<Buffer>>
public get(url: string, options: HTTPOptions & { responseType: "json" }): Promise<HTTPResponse<JSON>>
public get(url: string, options: HTTPOptions & { responseType: "text" }): Promise<HTTPResponse<string>>
public get(url: string, options?: HTTPOptions): Promise<HTTPResponse>
public get(url: string, options?: HTTPOptions): Promise<HTTPResponse> {
return null!
}
}
let http = new HTTP({ responseType: "text" });
http.get("", { responseType: "text" }) // string
http.get("") // expected string, this does not work
解决方案
问题的第一部分是在构造函数中捕获类型信息。我们需要知道responseType
创建类时传递的类型。每当我们需要捕获呼叫站点信息时,通常可以使用泛型类型参数。
所以我们可以将类更改为:
class HTTP<TResponseDefault extends ResponseType = "json"> {
constructor(public options: HTTPOptions & { responseType?: TResponseDefault }) {
this.options.responseType = options.responseType ?? "json" as TResponseDefault; // Default response type is JSON
}
}
这将确保我们在方法中有必要的信息,因为我们在传入HTTP
时捕获了任何已创建对象的类型:responseType
let httpJson = new HTTP({}); // HTTP<"json">
let httpText = new HTTP({ responseType: "text"}); // HTTP<"text">
现在我们有了这些信息,我们可以看到如何使返回类型依赖于它。虽然重载通常是一个很好的第一种方法,但在这种情况下,因为默认值可以来自类或调用,并且因为有很多选项和方法,所以我会采用另一种方法。
我们可以做的是使用泛型类型参数使方法泛型以捕获响应类型。此泛型类型参数将默认为类类型参数。因此,如果在调用中未指定响应类型,TResponseDefault
则将使用。然后我们可以使用这个类型参数来索引一个我们从响应类型映射到实际类型的接口:
interface TypeToResponseType {
"buffer" : HTTPResponse<Buffer>
"json" : HTTPResponse<object>
"text" : HTTPResponse<string>
}
class HTTP<TResponseDefault extends ResponseType = "json"> {
constructor(public options: HTTPOptions & { responseType?: TResponseDefault }) {
this.options.responseType = options.responseType ?? "json" as TResponseDefault; // Default response type is JSON
}
public get<TResponse extends ResponseType = TResponseDefault>(url: string, options?: HTTPOptions & { responseType?: TResponse }): Promise<TypeToResponseType[TResponse]>
public get(url: string, options?: HTTPOptions): Promise<HTTPResponse> {
return null!
}
}
let httpJson = new HTTP({}); // HTTP<"json">
let httpText = new HTTP({ responseType: "text"}); // HTTP<"text">
let a = httpJson.get("", { responseType: "text" }) // string
let b = httpJson.get("") // object
let c = httpText.get("") // string
推荐阅读
- javascript - 我的问题是关于在 Javascript 中将文本框值存储在数组中并将它们求和
- reactjs - For...in 循环在发送到 Firestore 时添加键而不是值
- python-hypothesis - 如何在假设中定义策略以生成一对相似的递归对象
- python-3.x - 取整数列表的平均值
- c# - C#如何分区并行foreach循环以迭代我的列表
- python - 如果发生特定异常,重新运行 try 块的简单方法?
- eclipse - 无法从 Eclipse 中以开发模式启动 Chrome
- c# - 单击DataGridView中的链接按钮时如何调用水晶报表查看器?
- python - 使用函数和for循环将文本与多个文件的列表进行比较
- php - 包含 database.php 不起作用 - 白屏