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

What is the right typescript definition for a specific javascript instantiation pattern

我目前正在研究 Paper.js 库打字稿定义,但我无法找到正确的方法来记录 API.

的某些部分

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

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 失败并显示错误:"Only a void function can be called with the 'new' keyword.",因为 Animal.Dog() 函数 return 类型是 Animal.

如果我将 Animal.Dog() 的 return 类型设置为 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 type extends Animal 但是库中没有 Animal.Dog,所以我发现这个解决方法误导了用户。

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

编辑

从@stramski 解决方案中阐述,我添加到问题中,事实上 Animal.Dog 可以有多个签名(例如 Animal.Dog()Animal.Dog(color)),我的目标是记录它们分开。

像这样的事情怎么样:

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

编辑

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

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

因为你是子类化.. 保持事情干净简洁很重要。上面写的方式,可以看到Dog是被造出来的动物,但是跟动物没有什么区别。在某些情况下,有些变量或方法会被覆盖。话虽这么说,我发现如果你实现类似于以下内容的东西会更好:

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

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

  communicate() { return "Barks"; }
}

从那里您可以覆盖方法或变量,以便正确区分狗与动物,与其他动物子 类。