Я хочу, чтобы все, что расширяет мой класс компонентов, могло иметь обработчики событий с проверкой типа, используя имя метода для определения типа обрабатываемого события.
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
.
Events = { MouseEvent, KeyboardEvent, }
бытьlet Events = { MouseInput, KeyboardInput, }
? Илиlet Events = { MouseEvent : MouseInput, KeyboardEvent: KeyboardInput, }
? - person Titian Cernicova-Dragomir   schedule 09.11.2018