对于特定的javascript实例化模式,正确的打字稿定义是什么?

时间:2018-11-19 18:07:15

标签: javascript typescript new-operator instantiation typescript-definitions

我目前正在研究Paper.js库打字稿的定义,但是我很难找到正确的方法来记录API的某些部分。

情况可以简化为以下情况:假设我们有一个Animal类,该类具有静态属性Dog,该属性用作该类的自定义构造函数:

var Animal = function(type) {};
Animal.Dog = function() {
    return new Animal('dog');
};

可以通过两种方式构建Animal实例:

var dog = new Animal('dog');

或者:

var dog = new Animal.Dog();

在两种情况下,我都需要将dog变量的类型推断为Animal


我第一次尝试:

declare class Animal
{
    constructor ( type )
    static Dog (): Animal
}

但是TSLint失败并显示以下错误:“只能使用'new'关键字调用void函数。”,因为Animal.Dog()函数的返回类型为Animal

如果我将Animal.Dog()的返回类型设置为void

declare class Animal
{
    constructor ( type )
    static Dog (): void
}

TSLint通过,但我得到void作为推断类型...


所以我尝试了另一种方式:

declare class Animal
{
    constructor ( type )
}

declare namespace Animal
{
    export class Dog extends Animal
    {
        constructor()
    }
}

这样,TSLint通过了,但是在以下情况下:

var dog = new Animal.Dog();

dog变量的推断类型是Animal.Dog,而不是我想要的Animal

这不是什么大问题,因为Animal.Dog类型扩展了Animal,但是库中没有Animal.Dog,所以我发现这种解决方法会误导用户。

有人知道更好的处理这种情况的方法吗?

编辑

我从@stramski解决方案中详细阐述了一个问题,即Animal.Dog可以有多个签名(例如Animal.Dog()Animal.Dog(color)),我的目标是分别记录它们。

2 个答案:

答案 0 :(得分:3)

那这样的事情呢?

declare class Animal
{
    constructor ( type )
    static Dog : (new () => Animal)
}

编辑

由于存在重载的构造函数,因此键入有所不同:

declare class Animal
{
    constructor ( type )
    static Dog : (new () => Animal) & (new (color) => Animal)
}

答案 1 :(得分:0)

由于您是子类化,所以保持整洁简洁非常重要。按照上面的方式,您可以看到Dog是一种动物,但与动物没有什么区别。在某些情况下,某些变量或方法会被覆盖。话虽如此,如果您实施类似于以下内容的方法,我会发现更好:

class Animal {
  constructor(){}
  communicate() { return "Makes Noise"; }
}

class Dog extends Animal {
  constructor(){
    super();
  }

  communicate() { return "Barks"; }
}

从那里您可以覆盖方法或变量,以正确区分Dog和Animal以及其他Animal子类。