Ограничивает член только принятием типа (не экземпляра), который расширяет или реализует другой тип [TypeScript] - PullRequest
0 голосов
/ 02 октября 2018

Мне нужна помощь с большим количеством абстракций в машинописи.

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

Например,

Следующий пример не представляет или не связан с реальной моделью данных, а является примером, иллюстрирующим цель.

interface Profession {
  work()
}

class Engineer implements Profession {
  work() {...}
}

class Doctor  {
  work() {...}
}

interface ProfessionRankingMap {
  top1ProfessionType: // Here is where I don't know how to constraint
  top2ProfessionType: // Here is where I don't know how to constraint
}

const classAProfessionRankingMap: ProfessionRankingMap {
  // This is okay, Type Engineer implements Profession interface
  top1ProfessionType: Engineer
  // This is bad, Type Doctor doesn't implement Profession interface
  top2ProfessionType: Doctor
}

const classBProfessionRankingMap: ProfessionRankingMap {
  // This is bad, [new Engineer()] returns an instance not a type
  top1ProfessionType: new Engineer()
  // This is bad, [new Doctor()] returns an instance not a type
  top2ProfessionType: new Doctor()
}

1 Ответ

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

Чтобы выразить класс в типе, вам нужна подпись конструктора:

interface ProfessionRankingMap {
  // The implementer must have a constructor with no args that returns Profession 
  top1ProfessionType: new () => Profession 
  top2ProfessionType: new () => Profession
}

const classAProfessionRankingMap: ProfessionRankingMap = {
  top1ProfessionType: Engineer,
  top2ProfessionType: Doctor
}

Ссылка на игровую площадку

Если мы хотим принимать классы с конструкторами, которые имеютлюбое количество аргументов, которые мы можем использовать new (... args:any[]) => Profession.

Вторая часть вашей проблемы немного сложнее.Typescript использует структурную типизацию для определения совместимости типов.Таким образом, структура класса имеет значение, а не предложение implements.Предложение implements просто поможет вам сообщать об ошибках при объявлении класса, гарантируя, что в нем есть все необходимые члены, поэтому вы получаете ошибки раньше, чем когда пытаетесь использовать класс, где ожидается интерфейс.

Это означает, что до тех пор, пока Doctor имеет всех членов Profession, невозможно предотвратить его передачу туда, где ожидается Profession.

Единственное решение - использоватьабстрактный класс с приватным членом.Закрытый член гарантирует, что никакие другие классы, кроме тех, которые расширяют абстрактный класс, не будут совместимы с типом абстрактного класса:

abstract class Profession {
  private _notStructural: undefined;
  abstract work(): void
}

class Engineer extends Profession {
    work() { }
}

class Doctor  {
    work() { }
}

interface ProfessionRankingMap {
  top1ProfessionType: new () => Profession
  top2ProfessionType: new () => Profession
}

const classAProfessionRankingMap: ProfessionRankingMap = {
  top1ProfessionType: Engineer,
  top2ProfessionType: Doctor // error
}

Ссылка для игровой площадки

...