Я хочу, чтобы все, что расширяет мой компонентный класс, могло иметь обработчики событий с проверкой типа, используя имя метода для определения типа события, которое они обрабатывают.
class UIEvent { }
class MouseInput extends UIEvent { }
class KeyboardInput extends UIEvent { }
let Events = {
MouseInput,
KeyboardInput,
}
Затем я использую сопоставленные типы для создания типа EventTarget
, который определяет сопоставление от имени к типу обработчика событий.
type EventTarget = {
[K in keyof typeof Events]?:
(event: InstanceType<typeof Events[K]>) => void;
}
EventTarget
может обрабатывать столько или мало типов событий, сколько они хотят, поэтому методы обработчика событий являются необязательными.
Затем я пытаюсь использовать это в классе компонентов, но не могу заставить компилятор принудительно реализовать интерфейс.
class Component implements EventTarget {
// The compiler has no problems with this, even though it violates
// the EventTarget interface...
MouseInput(event: KeyboardInput) {
}
}
Я сильно подозреваю, что пытаюсь здесь работать против структурной типизации, потому что, как только я добавляю свойство, отличающее MouseEvent
от KeyboardEvent
, проверки типов работают.
class UIEvent<T> { t: T }
class MouseInput extends UIEvent<"MouseInput"> {}
class KeyboardInput extends UIEvent<"KeyboardInput"> {}
Это работает, но я бы предпочел использовать конструктор события в качестве дискриминатора, а не добавлять отдельный тип свойства.
И, наконец, я хочу расширить этот контракт на подтипы класса компонента.
class Clickable extends Component {
// This should also fail to typecheck, but interfaces aren't inherited
MouseInput(event: KeyboardInput) {
}
}
Самое близкое, что я могу получить прямо сейчас, - это явным образом реализовать каждый подтип EventTarget
.