Может ли Typescript вывести тип экземпляра класса расширения, созданного методом его базы? - PullRequest
0 голосов
/ 16 октября 2018

Рассмотрим следующий фрагмент 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

Животные могут иметь детей, и ребенок должен быть того же вида, что и родитель, т.е. должен быть экземпляром того же класса, что и родитель,Как назначить типы в этой ситуации, чтобы Typescript знал, что sorachiJr: Cat?

Приведенный выше фрагмент кода не работает. Строка return new this.constructor(name) выдает ошибку [ts] Cannot use 'new' with an expression whose type lacks a call or construct signature.в кодексе VS.Единственное решение, которое я смог найти и понять, - это заменить this.constructor(name) на (<any>this.constructor)(name) или (<any>this).constructor(name), но тогда для sorachiJr будет выведен тип any, а не Cat.Я попытался привести к typeof this, а не any, но получил ошибку [ts] Cannot find name 'this'.

Как мне убедить Typescript в том, что рождение детей - это операция по сохранению вида?

1 Ответ

0 голосов
/ 16 октября 2018

Сохранить тип класса, к которому был вызван метод, легко, мы просто используем полиморфный тип this.Чтобы убедить ts, что constructor будет конструктором, который принимает string и возвращает экземпляр того же типа, что и текущий класс, требуется утверждение типа

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."); 

Примечание Typescriptне может подтвердить тот факт, что конструктор производного класса ожидает только один параметр string, для этого может потребоваться больше или меньше параметров.Это делает этот конструктор небезопасным.

...