😸
Element.addEventListener で Event 以外を指定したときのTypeScript のエラー対応
事象
TypeScript で Element
要素に対して、addEventListener でイベントを指定する。
その際に第2引数の匿名関数の引数 event
の型を Event
ではなく、 TouchEvent
にするとコンパイルエラーが発生した。
const container = document.getElementsByClassName("container")[0];
container.addEventListener("touchStart", (event: TouchEvent) => {
...
});
エラーメッセージ
TS2769: No overload matches this call.
Overload 1 of 2, '(type: "fullscreenchange" | "fullscreenerror", listener: (this:
Element, ev: Event) => any, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
Argument of type 'string' is not assignable to parameter of type '"fullscreenchange" | "fullscreenerror"'.
Overload 2 of 2, '(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void', gave the following error.
Argument of type '(event: TouchEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '(event: TouchEvent) => void' is not assignable to type 'EventListener'.
Types of parameters 'event' and 'evt' are incompatible.
Type 'Event' is missing the following properties from type 'TouchEvent': altKey, changedTouches, ctrlKey, metaKey, and 6 more.
原因
TypeScript の strictFunctionTypes
の設定によるもの。(TypeScript 2.6 で追加)
対策
対策1 tsconfig.json の設定変更
tsconfig.jsonで
"strictFunctionTypes": false
と設定して、 String Function Types を無効にする。
<TouchEvent>
の利用
対策2 アサーション 引数は Event
として、関数内部で <TouchEvent>event
で置き換える。
const container = document.getElementsByClassName("container")[0];
container.addEventListener("touchStart", (event: Event) => {
const touchEvent = <TouchEvent>event;
...
});
as EventListener
の利用
対策3 アサーション 引数は TouchEvent
として、関数にアサーション as EventListener
を指定する。
const container = document.getElementsByClassName("container")[0];
container.addEventListener("touchStart", ((event: TouchEvent) => {
...
}) as EventListener);
is
を利用する。
対策4 TouchEventであることをチェックする関数 isTouchEvent
を作成する。
引数は Event
として、関数内部で isTouchEvent を呼び出す。
その後、 event
は 型 TouchEvent
に絞り込まれる。
function isTouchEvent(event: Event): event is TouchEvent {
return 'touches' in event;
}
const container = document.getElementsByClassName("container")[0];
container.addEventListener("touchStart", (event: TouchEvent) => {
if (!isTouchEvent(event)) {
throw new Error('not a touch event');
}
...
});
参考サイト
Discussion