typescript 类型“Function”没有构造签名,ts

agxfikkp  于 2023-02-05  发布在  TypeScript
关注(0)|答案(1)|浏览(600)

我试图将我的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;
zsbz8rwp

zsbz8rwp1#

你的代码的潜在问题是你可以用一个子类来扩展一个基类,这个子类的构造函数不接受与基类相同的参数列表,所以new this.constructor(...args)对于任何args来说都是不安全的。例如:

class StringPoint extends Point2D {
    constructor(x: string, y: string) {
        super(x.trim().length, y.trim().length);
    }
}

const s = new StringPoint("abc", "defgh  ");
console.log(s.x) // 3
console.log(s.y) // 5

StringPoint类派生自Point2D,但它的构造函数接受两个 * string * 而不是两个数字,并将这些字符串称为“trim() method”。到目前为止,一切都很好,但当我们调用使用new this.constructor的基类方法时,事情在运行时爆炸了:

console.log(s.multiply(2)) // 💥 ERROR! x.trim is not a function

这是因为s.multiply(2)最终调用了new this.constructor(6, 10),但是因为thisStringPoint的示例,那么this.constructor就是StringPoint,所以new StringPoint(6, 10)被调用了,这意味着数字被传递给期望字符串的东西,而number没有trim()方法。
这里正确的修复方法可能是直接使用Point2D构造函数,而不是询问示例它的构造函数是什么:

public add(that: Point2D) {
    return new Point2D(this.x + that.x, this.y + that.y); // okay
}

public subtract(that: Point2D) {
    return new Point2D(this.x - that.x, this.y - that.y); // okay
}

public multiply(scalar: number) {
    return new Point2D(this.x * scalar, this.y * scalar); // okay
}

这样做是因为Point2D是一个特定的类构造函数,可以接受两个数字,我上面的StringPoint示例现在可以正常工作,因为基类方法生成基类的示例,甚至不尝试构造可能不兼容的子类的新示例:

const s = new StringPoint("abc", "defgh  ");
console.log(s.x) // 3
console.log(s.y) // 5
console.log(s.multiply(2)) // okay, {x: 6, y: 10}

这里的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引擎都会出现运行时错误。调用不带newclass构造函数将给予TypeError(请参见ECMAScript规范的相关部分)。
因此,在处理TypeScript中的constructor属性时要小心!
Playground代码链接

相关问题