Проблема в том, что ваша addEventListener()
не знает, как параметр type
относится к подтипу Event
, который handler
должен принять. В стандартном библиотечном файле TypeScript lib.dom.d.ts
отдельным EventTarget
типам дано очень точное отображение c от type
до handler
. Например, сигнатура интерфейса Window
для его addEventListener
метода выглядит следующим образом :
addEventListener<K extends keyof WindowEventMap>(
type: K,
listener: (this: Window, ev: WindowEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): void;
, где WindowEventMap
- это , определенное здесь как большое отображение между type
именами и Event
типами. В частности, для ключа mousedown
тип значения свойства равен MouseEvent
. Таким образом, когда вы вызываете
window.addEventListener('mousedown', (event: MouseEvent) => {
console.log(event.pageX);
});
, все работает, потому что K
выводится как "mousedown"
, и поэтому параметр handler
ожидает MouseEvent
.
Без этого В зависимости от типа отображаемой информации, типизация выглядит следующим образом: type
равно string
, а listener
равно (event: Event)=>void
. Но, как вы видели, вы не можете просто передать (event: MouseEvent)=>void
параметру, ожидающему (event: Event)=>void
, потому что это вообще небезопасно. Если вы дадите мне функцию, которая принимает только MouseEvent
с, я не смогу использовать ее как функцию, которая принимает все Event
с. Если я попытаюсь, и функция, которую вы мне дадите, получит доступ к чему-то вроде свойства pageX
, я могу получить ошибку времени выполнения.
Такое ограничение на аргументы функции было добавлено в TypeScript 2.6 как --strictFunctionTypes
опция компилятора . Если вы отключите эту опцию компилятора, ваша ошибка должна исчезнуть, но я не рекомендую вам это делать.
Вместо этого, если вы хотите ослабить ввод только для функции addEventListener
, вы можете сделать ее обобщенной. c в подтипе Event
, например:
function addEventListener<T extends EventTarget, E extends Event>(
element: T, type: string, handler: (this: T, evt: E) => void) {
element.addEventListener(type, handler as (evt: Event) => void);
}
Тогда ваш код скомпилируется:
addEventListener(window, "mousedown", (event: MouseEvent) => {
console.log(event.pageX);
});
Но помните: эта типизация слишком свободна, чтобы перехватывать ошибки, например как это:
addEventListener(document.createElement("div"), "oopsie",
(event: FocusNavigationEvent) => { console.log(event.originLeft); }
);
Если вы попробуете это прямо на HTMLDivElement
, вы получите ошибку:
document.createElement("div").addEventListener("oopsie",
(event: FocusNavigationEvent) => { console.log(event.originLeft); }
); // error! oopsie is not acceptable
, которая не будет решена, пока вы не исправите оба type
параметр
document.createElement("div").addEventListener("blur",
(event: FocusNavigationEvent) => { console.log(event.originLeft); }
); // error! FocusNavigationEvent is not a FocusEvent
И использовал соответствующий Event
подтип
document.createElement("div").addEventListener("blur",
(event: FocusEvent) => { console.log(event.relatedTarget); }
); // okay now
Итак, это примерно настолько, насколько я могу go здесь. Вы можете попытаться сделать огромное сопоставление из всех известных EventTarget
типов со всеми правильными type
параметрами для каждой цели, а затем со всеми правильными Event
подтипами для каждого EventTarget
/ type
пары и имеют единственную обобщенную функцию c addEventListener
, которая работает ... но по размеру она будет сравнима с файлом lib.dom.d.ts
, и я не склонен тратить на это слишком много времени. Если вам нужна безопасность типов, вам, вероятно, лучше не использовать эту конкретную абстракцию. В противном случае, если у вас все в порядке с компилятором, пропускающим некоторые несоответствия, то приведенная выше типизация может быть способом go.
Хорошо, надеюсь, это поможет; удачи!
ссылка на игровую площадку