Как я должен заполнить файл объявления модуля для библиотеки JS с использованием методов наследования, несовместимых с Typescript?

#typescript #.d.ts

#typescript #.d.ts

Вопрос:

Я заполняю объявление модуля сторонней библиотеки JS, и библиотека содержит подклассы, которые (по подсчетам Typescript) несовместимо переопределяют методы родительского класса. Существует много примеров этого, но простой пример следующий:

Базовый класс:

 class Entity {
  ...

  /**
  * Test whether a given User has permission to perform some action on this Entity
  * @param {User} user           The User requesting creation
  * @param {string} action       The attempted action
  * @return {boolean}            Does the User have permission?
  */
  can(user, action) {
    ...
  }
}
 

Подкласс:

 class User extends Entity {
  ...

  /**
   * Test whether the User is able to perform a certain permission action. Game Master users are always allowed to
   * perform every action, regardless of permissions.
   *
   * @param {string} permission     The action to test
   * @return {boolean}              Does the user have the ability to perform this action?
   */
   can(permission) {
     ...
   }
}
 

Как я могу точно представить переопределенные методы, подобные приведенным выше, без указания tsc на очевидное? Или мне придется каким-то образом «лгать» и искажать связь между Entity и User ?

Комментарии:

1.Судя по представленному коду, User не является подклассом Entity

2. @spender Спасибо, исправлено. Я вручную набрал усеченный код для этого вопроса.

Ответ №1:

Вы можете создать тип, который удаляет can свойство из базового Entity типа, а затем присваивает Entity переменной этого типа.

Теперь вы можете создать новый класс, производный от этой переменной-ссылки на «класс».

Это нарушает полиморфизм (как и первоначальный разработчик). Это ужасно. Не делайте этого. Стисни зубы и реорганизуй свой беспорядок.

 class Entity {
    can(user: string, action: string) {
        console.log(user, action)
    }
}

type PartialEntity = new () => { [P in Exclude<keyof Entity, 'can'>]: Entity[P] }

const EntityNoCan: PartialEntity = Entity;

class User extends EntityNoCan {
    can(permission: number) {
        console.log(permission)
    }
}
 

Комментарии:

1. Как бы вы порекомендовали мне провести рефакторинг «моего беспорядка»? Или ты обращаешься на королевское «ты»?

2. Что ж, похоже, вы унаследовали дизайн, который злоупотребляет слабой природой наследования JavaScript. Используя такой подход, созданные объекты нарушают принцип подстановки Лискова, сводя на нет весь смысл наследования. Это недостаток в базовом дизайне, который на моем месте я бы сделал крюк, чтобы исправить.

Ответ №2:

Похоже, что a // @ts-ignore — действительно единственный вариант здесь. Другое предлагаемое решение неприменимо к объявлениям типов.