javascript - 在 TypeScript 类上添加抽象/可继承的静态构造函数辅助方法
问题描述
我有一个抽象 API 类,其中包含一些用于我们的应用程序的基本 api 逻辑,我在其他各种类中进行了扩展:
interface Options {
authToken?: string;
ip?: string;
endpointPrefix?: string;
}
abstract class AbstractApi {
private authToken?: string;
private ip?: string;
private endpointPrefix?: string;
constructor({
ip = undefined,
authToken = undefined,
endpointPrefix = '',
}: Options) {
this.authToken = authToken;
this.ip = ip;
this.endpointPrefix = endpointPrefix;
}
protected async get() {
// ...
}
protected async post() {
// ...
}
}
class TodosApi extends BaseApi {
constructor() {
super({ endpointPrefix: '/todos' });
}
getTodos(/* ... */) {
this.post(/* ... */);
}
}
我想确保 AbstractApi 的每个实例都有一个静态便利构造函数:.new()
。例如const todos = await TodosApi.new().getTodos()
。
我如何确保每个孩子都自动使用此方法?
我尝试过但没有奏效的一些事情:
static create(data) {
return new this.constructor(data);
}
static create(data) {
return new this(data)
}
解决方案
很难确切地知道“没有工作”是什么意思。你的意思是你有一个编译器错误?或者它在运行时不起作用?或两者?无论如何,我将尝试继续并希望解决您面临的问题:
由于this
静态方法的上下文将是类构造函数而不是类实例,因此您将需要使用new this()
而不是new this.constructor()
. 假设具体的子类将有不同的构造函数参数列表要求,您的静态create()
方法可能应该采用一个rest 参数。所以在运行时你希望它看起来像这样:
static create(...args) {
return new this(...args);
}
现在我们只需要为该方法提出适当的类型来满足编译器并在您尝试使用它时产生合理的行为。对于实例方法,显而易见的解决方案涉及所谓的多态this
,其中this
类型表示“无论当前类实例类型是什么”,即使对于子类也是如此。不幸的是,(从 TS3.7 开始)静态方法没有类似的多态性this
。相反,我们需要使用涉及泛型和参数的解决方法:this
static create<A extends any[], R>(this: new (...args: A) => R, ...args: A) {
return new this(...args);
}
这意味着create
将作为某个具体构造函数类型的方法调用,该构造函数类型接受一些参数列表A
并产生一些实例类型R
。(您可以限制R
扩展AbstractApi
,但这里不需要)。让我们看看它是否有效:
TodosApi.create().getTodos(); // okay
TodosApi.create("bad argument"); // error: expected 0 arguments, got 1
AbstractApi.create({}); // error: this context of create does not match
所以你想要的使用效果很好。您可以看到它TodosApi.create()
需要与构造函数相同的参数列表TodosApi
(即没有参数),因此如果您将错误的内容传递给它,则会收到错误消息。如果您尝试create()
直接调用 on ,编译器会给您一个错误AbstractApi
,因为create()
它要求其this
上下文是可构造的,并且AbstractApi
是抽象的,因此不可构造。
那对你有用吗?希望有帮助;祝你好运!