I have class ChildA
and a class ChildB
and a class Base
.
我有一个A班,一个B班和一个基础班。
ChildA
and ChildB
inherits from Base
. The constructor of Base
takes 1 parameter, called id
.
ChildA和ChildB继承自Base。Base的构造函数接受1个参数,称为id。
I need to add a method, validate
to Base
class, so that:
我需要添加一个方法Valify to Base类,以便:
Every class that inherits from Base
should be forced to implement.
This method will be executed before I have an id
which i can use in order to create an instance of ChildA
/ ChildB
.
Because of #1, it feels like this method should be abstract.
Because of #2, it feels like this method should be static.
However, typescript doesn't support abstract static functions.
由于#1,我觉得这个方法应该是抽象的。由于#2,我觉得这个方法应该是静态的。但是,TypeScrip不支持抽象的静态函数。
Eventually, the usage should be that the validate
methods of ChildA
and ChildB
are invoked from some other method of Base
, let's call it bla
, Something like:
最终,用法应该是从Base的其他方法调用ChildA和ChildB的验证方法,我们称其为bla,类似于:
abstract class Base {
id: string;
protected static abstract validate(): boolean;
constructor(id: string) {
this.id = id;
}
bla() {
const r = (this.constructor as typeof Base).validate();
// do something with r
}
}
class ChildA extends Base {
protected static validate(): boolean {
// validate stuff
return true;
}
}
class ChildB extends Base {
protected static validate(): boolean {
// validate stuff
return false;
}
}
The problem is that I can't define validate
as both abstract and static so I'm not sure how I can achieve what I need, maybe I can use interface for it, but not sure how exactly.
问题是我不能同时将验证定义为抽象和静态,所以我不确定如何才能实现我需要的东西,也许我可以使用接口来实现它,但不确定具体如何实现。
I'm not writing the code from scratch, so I have limited freedom to change things.
我不是从头开始编写代码,所以我改变事情的自由有限。
更多回答
Where are you going to call validate
as a static method? It is that place where you'll need to require the concrete class to implement the method, regardless whether it is declared on Base
or not. Admittedly, you'll get the type error in the "wrong" place, i.e. where you are calling the method on an incompatible receiver, not where you are defining the concrete class to inherit from Base
, but at least it's still typesafe.
您将在哪里将Valify作为静态方法调用?无论它是否在Base上声明,您都需要使用具体类来实现该方法。诚然,您会在“错误”的地方得到类型错误,即在不兼容的接收器上调用方法,而不是在定义要从Base继承的具体类的地方,但至少它仍然是类型安全的。
I did it @jcalz
我做到了@jcalz
I think this is discussed in depth at ms/TS#34516 and while there are various workarounds, none enforce that subclasses implement the static method the way you want. And it's not obvious what should be allowed in general, so this is a tricky thing to do properly. Personally I might just give up and write a runtime-only check like this, which at least lets you use the static method. Let me know if this fully addresses the question and I should write up an answer, or if I'm missing something (and if so, what)
我认为在MS/TS#34516中已经对此进行了深入的讨论,虽然有各种变通方法,但没有一个强制子类以您想要的方式实现静态方法。一般来说,什么应该被允许并不是很明显,所以这是一件很难做的事情。就我个人而言,我可能会放弃,像这样编写一个仅限运行时的检查,这至少允许您使用静态方法。让我知道这是否完全解决了问题,我应该写下答案,或者我是否遗漏了什么(如果是,遗漏了什么)
Thank you, I understand the solution you're suggesting, but I don't think the runtime check is good enough (at this point at least). Can't I somehow use interface instead of the abstract part?
谢谢,我理解您建议的解决方案,但我认为运行时检查还不够好(至少在这一点上)。难道我不能使用接口而不是抽象部分吗?
What do you mean by "somehow use interface"? You can define an interface the static side needs to implement but you can't require subclasses to conform to it; there's no "extends static
" either. Perhaps you just want a class factory function instead of abstract
at all, like this playground link shows. Do you want to see that written up as an answer instead?
你说的“以某种方式使用界面”是什么意思?您可以定义静态端需要实现的接口,但不能要求子类遵守它;也没有“扩展静态”。也许您只想要一个类工厂函数,而不是抽象的,就像这个操场链接所示。你想看到这句话被写成答案吗?
abstract class Base {
id: string;
protected abstract validate(): boolean;
constructor(id: string) {
const r = this.bla();
console.log(r);
this.id = id;
}
bla() {
const r = this.validate();
// do something with r
return r;
}
}
class ChildA extends Base {
protected validate(): boolean {
// validate stuff
return true;
}
}
class ChildB extends Base {
protected validate(): boolean {
// validate stuff
return false;
}
}
const childa = new ChildA('1');
const childb = new ChildB('2');
This should hopefully fulfill the two criteria you have. I've opted to keep the methods protected
这将有望满足您拥有的两个标准。我选择保护这些方法
Every class that inherits from Base should be forced to implement.
应该强制实现从Base继承的每个类。
This method will be executed before I have an id which i can use in order to create an instance of ChildA / ChildB.
此方法将在我拥有可以用来创建ChildA/ChildB的实例的id之前执行。
If you need the validate
method to be static, so you can call it before you create a child, then you could do one of two things
如果您需要验证方法是静态的,以便您可以在创建子对象之前调用它,则可以执行以下两种操作之一
- Have logic in the constructor of the Child which has validation logic. If it's in valid, it can throw an error.
- Create a builder object which can build and validate your params before it builds a child. https://refactoring.guru/design-patterns/builder
更多回答
Thank you, but I can't do #1 cause I need the id
in order to create an instance and there's no id
at this point in the flow. Regarding #2, I guess it's possible to use builder, but this change is relatively big. I might end up doing something like it but wanted to check if there's a shorter, more elegant way of approaching it.
谢谢,但是我不能做#1,因为我需要id来创建一个实例,而在流中的这一点上没有id。关于第二点,我想使用Builder是可能的,但这个变化相对较大。我可能最终会做类似的事情,但我想看看有没有更短、更优雅的方法来接近它。
我是一名优秀的程序员,十分优秀!