我试图将我的JS重写为TS。我有一个名为Point2D的类,用于操作二维点。我得到了一个Type 'Function' has no construct signatures.ts(2351)
的错误。在移动到TS时,我做错了什么?
class Point2D {
x: number;
y: number;
public constructor(x: number = 0, y: number = 0) {
this.x = x;
this.y = y;
}
/**
* Translate this point by that point
*
* @param {Point2D} that
*/
public add(that: Point2D) {
return new this.constructor(this.x + that.x, this.y + that.y); // ERROR
}
public subtract(that: Point2D) {
return new this.constructor(this.x - that.x, this.y - that.y); // ERROR
}
/**
*
* @param {number} scalar
*/
public multiply(scalar:number) {
return new this.constructor(this.x * scalar, this.y * scalar); // ERROR
}
}
export default Point2D;
1条答案
按热度按时间zsbz8rwp1#
你的代码的潜在问题是你可以用一个子类来扩展一个基类,这个子类的构造函数不接受与基类相同的参数列表,所以
new this.constructor(...args)
对于任何args
来说都是不安全的。例如:StringPoint
类派生自Point2D
,但它的构造函数接受两个 * string * 而不是两个数字,并将这些字符串称为“trim()
method”。到目前为止,一切都很好,但当我们调用使用new this.constructor
的基类方法时,事情在运行时爆炸了:这是因为
s.multiply(2)
最终调用了new this.constructor(6, 10)
,但是因为this
是StringPoint
的示例,那么this.constructor
就是StringPoint
,所以new StringPoint(6, 10)
被调用了,这意味着数字被传递给期望字符串的东西,而number
没有trim()
方法。这里正确的修复方法可能是直接使用
Point2D
构造函数,而不是询问示例它的构造函数是什么:这样做是因为
Point2D
是一个特定的类构造函数,可以接受两个数字,我上面的StringPoint
示例现在可以正常工作,因为基类方法生成基类的示例,甚至不尝试构造可能不兼容的子类的新示例:这里的
s.multiply(2)
是一个Point2D
,但不是一个StringPoint
。请注意,the
constructor
property of objects在TypeScript中的类型不幸地不是非常有用;this.constructor
被视为Function
或“无类型调用”类型。这两种类型都太 * 严格 * 了,因为您 * 可能 * 知道Function
中缺少的构造函数属性的信息(如在X1 E2 F1 X中所讨论的)并且太 * 松散 *,因为,尽管X1 M25 N1 X被拒绝,您可以使用任何参数调用Function
(如microsoft/TypeScript#48284中所述)。这意味着,如果去掉
new
操作符,只调用this.constructor(6, 10)
而不是new this.constructor(6, 10)
,那么这个问题就可以得到解决,尽管这确实会阻止编译器发出错误。这种胜利将是短暂的,因为它保证了大多数JavaScript引擎都会出现运行时错误。调用不带new
的class
构造函数将给予TypeError
(请参见ECMAScript规范的相关部分)。因此,在处理TypeScript中的
constructor
属性时要小心!Playground代码链接