我是一位在Typescript方面苦苦挣扎的Java开发人员。 我有一个名为Shape的抽象类,以及两个继承自它的具体类:Square和Circle。我还想将构造函数隐藏在那些类中,并创建一个工厂方法getNewShape,该方法将基于一个参数来决定使用哪个具体的c'tor。在Java中,我只需写(在Shape中):
public static <T extends Shape> T getNewShape(T reference){
// my logic
reference = T.class.getInstance();
return reference;
}
在Typescript中,我现在想像这样使用它:
let myShape = Square.getNewShape(myShape);
我阅读了其他可以使用的问题:
in the consumer:
let myShape = Square.getNewShape(myShape, Square);
in Shape:
public static <T extends Shape>(ref: T, type): T{
//my logic
reference = new type();
return reference;
}
但是我更喜欢如果我已经从具体的类中调用getNewShape,则不需要在参数中添加Type,而打字稿只需从T推断出来即可。
更新:添加完整的代码:
class Shape {
constructor(){
}
public static getNewShape<T extends Shape>(ref: T, type: new() => T): T{
if(ref) {
ref.clear();
}
ref = new type();
return ref;
}
protected clear(){
console.log('clearing');
}
}
class Circle extends Shape{
protected constructor(){
super();
}
}
class Square extends Shape{
protected constructor(){
super();
}
}
class App {
private _circle: Circle = null;
constructor(){
}
public setup(){
this._circle = Circle.getNewShape(this._circle, Circle);
}
}
答案 0 :(得分:0)
这是前进的一种可能方法:
abstract class Shape {
public static getNewShape<T extends Shape>(
this: { prototype: T }, // ctors have a strongly typed prototype
ref: T
): T {
if (ref) {
ref.clear();
}
// assert that this is a constructor
ref = new ((this as any) as new () => T)();
return ref;
}
protected clear() {
console.log("clearing");
}
}
class Circle extends Shape {
private constructor() {
super();
}
radius: number = 0; // add property
}
class Square extends Shape {
private constructor() {
super();
}
side: number = 0; // add property
}
class App {
private _circle: Circle = null!; // yeah, how do you get this?!
constructor() {}
public setup() {
this._circle = Circle.getNewShape(this._circle); // okay
Square.getNewShape(this._circle); // error!
}
}
相关的部分是:
将构造函数标记为protected
或private
时会遇到很大的限制,并且不能同时使用两种方法。如果Circle
的构造函数不是公共的,则不能在Shape.getNewShape()
内部调用它,因为即使受保护的构造函数也只能从子类访问,而不能从超类访问。幸运的是,有type assertions使我们可以在Shape.getNewShape()
的实现中覆盖编译器的抱怨。当然,这不是类型安全的。所以你必须要小心。
不是将T
的构造函数称为new()=>T
,(如您所述)不适用于private
或protected
构造函数,我们可以利用这样的事实,即TypeScript中的类构造函数具有强类型的prototype
属性,该属性也具有T
类型,无论构造函数是否为公共。因此,new()=>T
结束了,{prototype: T}
结束了。请注意,这并不能正确地传达出构造函数的参数为零的事实……再结合上面的类型断言,这意味着您需要如果Square
没有参数,请确保Circle
和new
在运行时不会爆炸。
请注意,您正在调用构造函数的静态方法,而不是将构造函数作为参数传递给SomeShape.getNewShape()
,这意味着构造函数应该是该调用的this
上下文。这样我们就可以new this()
了。而且我们可以使用this
parameter来防止用户在错误的构造函数上调用该方法(Square.getNewShape(someCircle)
应该是错误的)。
那些是有效成分。我仍要提及的次要细节:
我在Circle
和Square
中添加了一些属性,以在结构上彼此区分,以及与Shape
和空类进行区分。如果要避免怪异,即使在使用示例代码的情况下,在TypeScript中也是important to do。 TypeScript中的类型系统是 structural ,而不是 nominal ;也就是说,类型是通过其形状而不是其名称识别的。如果类型/接口/类A
和B
共享相同的属性键和值,则尽管名称不同,但编译器仍将它们视为相同的类型/接口/类。
我仍然不确定如果构造函数不可访问,那么有人如何首次有效引用Square
或Circle
实例。对我来说,这似乎是一个引导问题。 Square.getNewShape(square)
在给定现有Square
的情况下给了我一个新的Square
,但是现有Square
从何而来?也许周围有Circle
和Square
的一些静态实例?或者,也许您还有另一种方法? ...或者,这只是在我身上发生,也许您认为null
是Shape
的有效实例。您不使用--strictNullChecks
或--strict
编译器选项吗?你真的应该然后,您可以将ref
注释为T | null
而不是T
,这样就明确了接受null
的意图。
所有这些,我真的建议不要隐藏构造函数,如果您只是要公开一个静态方法来调用它们的话。这非常复杂,我不知道它能为您带来什么。相反,可以考虑只将构造函数公开为public
并在抽象getNewShape()
构造函数内进行Shape
中所做的所有整理工作:
abstract class Shape {
constructor(ref: Shape | null) {
if (ref) {
ref.clear();
}
}
protected clear() {
console.log("clearing");
}
}
class Circle extends Shape {
constructor(ref: Circle | null) {
super(ref);
}
radius: number = 0; // add property
}
class Square extends Shape {
constructor(ref: Square | null) {
super(ref);
}
side: number = 0; // add property
}
class App {
private _circle: Circle | null = null;
constructor() {}
public setup() {
this._circle = new Circle(this._circle); // okay
new Square(this._circle); // error!
}
}
在我看来,这是一样的,并且不会因为试图强制TypeScript做它不想做的事情而受苦。
好的,希望能有所帮助;祝你好运!