Typescript可以推断通过其基础方法实例化的扩展类实例的类型吗?

fmg*_*fmg 5 javascript constructor type-inference subclass typescript

考虑以下Typescript代码段:

class Animal {
  constructor(name: string) {
    this.name = name;
  }
  name: string;

  haveBaby(name: string): ?? return type ?? {
    return new this.constructor(name); // Error
  }
}

class Cat extends Animal {}
class Dog extends Animal {}
class Gerbil extends Animal {} // etc.

let sorachi = new Cat("Sorachi"); // a: Cat
let sorachiJr = a.haveBaby("Sorachi Jr."); // I want: sorachiJr: Cat
Run Code Online (Sandbox Code Playgroud)

动物可以有婴儿,而婴儿应与父母具有相同种类的动物,即应与父母属于同一类的实例。在这种情况下,如何分配类型,以便Typescript知道sorachiJr: Cat呢?

上面的代码段不起作用。该行在VS Code中return new this.constructor(name)产生错误[ts] Cannot use 'new' with an expression whose type lacks a call or construct signature.。我能找到和理解的唯一解决方案是更换this.constructor(name)(<any>this.constructor)(name)(<any>this).constructor(name),但随后推断类型sorachiJrany,太,而不是Cat。我尝试强制转换为,typeof this而不是any,但出现了错误[ts] Cannot find name 'this'

我如何才能说服Typescript相信生育是一种保护物种的活动?

Tit*_*mir 5

保留调用方法的类的类型很容易,我们只需使用多态类型即可this。要说服 ts constructor 将是一个接受 astring 并返回与当前类相同类型的实例的构造函数,需要类型断言

type AnimalConstructor<T extends Animal> = new (name: string) => T
class Animal {
    constructor(name: string) {
        this.name = name;
    }
    name: string;

    haveBaby(name: string): this  {
        return new (this.constructor as AnimalConstructor<this>)(name); 
    }
}

class Cat extends Animal {}
class Dog extends Animal {}
class Gerbil extends Animal {} // etc.

let sorachi = new Cat("Sorachi"); // a: Cat
let sorachiJr = sorachi.haveBaby("Sorachi Jr."); 
Run Code Online (Sandbox Code Playgroud)

注意Typescript 无法验证派生类构造函数仅需要单个string参数这一事实,它可能需要更多或更少的参数。这使得这个构造函数不是类型安全的。