#typescript #generics #inheritance #typescript-generics
Вопрос:
Рассмотрим следующие типы :
abstract class IProject { /* Shared stuff */ }
type ActionList<TProject extends IProject> = Array<{ (project: TProject): void }>;
Представьте, что это библиотека, которая будет опубликована; и пользователи должны расширить IProject
класс, как показано ниже :
class ProjectA extends IProject {
public constructor(public readonly actions: ActionList<ProjectA>) { }
/* ProjectA stuff */
}
class ProjectB extends IProject {
public constructor(public readonly actions: ActionList<ProjectB>) { }
/* ProjectB stuff */
}
Предполагается, что расширенные классы должны иметь actions
поля и иметь свой собственный тип, а не суперкласс.
Первая цель состоит в том, чтобы заставить пользователей включать это поле и без избыточности повторять это поле в каждом подклассе.
Просто для ясности, для суперкласса нормально не знать тип дочернего элемента; только в конструкторах подклассов требуется использовать тип подкласса в их ActionList
s.
Я могу сделать следующее, чтобы достичь первой цели :
type ActionList<TProject> = Array<{ (project: TProject): void }>;
abstract class IProject<TChild> {
protected constructor(public readonly actions: ActionList<TChild>) { }
/* Shared stuff */
}
Теперь пользователи должны расширить свои классы, как показано ниже, что является грязным :
class ProjectA extends IProject<ProjectA> {
public constructor(actions: ActionList<ProjectA>) { super(action); }
/* ProjectA stuff */
}
class ProjectB extends IProject<ProjectB> {
public constructor(actions: ActionList<ProjectB>) { super(action); }
/* ProjectB stuff */
}
Но это на самом деле не заставляет пользователей использовать тип своего собственного класса в его ActionList
параметрах типа, потому что в этом случае TChild
может быть любой тип; в то время как я хочу, чтобы они были подклассами IProject
; чтобы быть более конкретным, точный подкласс, который расширяется IProject
.
Я могу отделить базовый интерфейс; как показано ниже :
interface IProjectBase {
/* Non-child related shared stuff */
}
type ActionList<TProject extends IProjectBase> = Array<{ (project: TProject): void }>;
abstract class IProject<TChild extends IProjectBase> implements IProjectBase {
protected constructor(public readonly actions: ActionList<TChild>) { }
/* Child related shared stuff */
}
Теперь TChild
он ограничен в расширении IProjectBase
, но теперь пользователи могут использовать его таким образом :
class ProjectA extends IProject<ProjectA> {
public constructor(actions: ActionList<ProjectA>) { super(action); }
/* ProjectA stuff */
}
class ProjectB extends IProject<ProjectA> {
public constructor(actions: ActionList<ProjectA>) { super(action); }
/* ProjectB stuff */
}
В то время ProjectB
как не следует разрешать использовать ProjectA
в качестве параметра типа; только себя.
Итак, каков обходной путь для этого ? Есть ли способ ограничить проекты, реализованные пользователями, включением в параметры типов только их собственных ActionList
типов ?
Обходной путь не требует использования универсальных методов, единственные цели здесь-не потерять информацию о типе и не заставить пользователей включать этот конкретный тип actions
поля в свои классы.
Комментарии:
1. Я не верю, что это возможно.