基于传递给
addEventListener
的类型,编译器知道事件处理程序应该是什么参数,在这种情况下是一个 KeyboardEvent
即使我在这里显式键入它,推理也有效。
const foo = document.getElementById("foo");
if (foo !== null) {
foo.addEventListener("click", (e: KeyboardEvent) => {
console.log("hey", e);
});
}
但是,在下面的代码块中,尽管仍然在
index 签名中坚定地将其键入为
HTMLElement
,addEventListener
失去了根据第一个参数切换事件类型的能力。
interface DOMElements {
[index: string]: HTMLElement;
}
class Baz {
$: DOMElements;
constructor() {
this.$ = {
bar: document.getElementById("bar") as HTMLElement;
};
}
}
const baz = new Baz();
baz.$.bar.addEventListener("click", (e) => {
console.log("hey", e);
});
如果我尝试用
显式输入它baz.$.bar.addEventListener("keyup", (e: KeyboardEvent) => {
console.log("hey", e);
});
我收到以下编译器错误。
Argument of type '(e: KeyboardEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '(e: KeyboardEvent) => void' is not assignable to type 'EventListener'.
Types of parameters 'e' and 'evt' are incompatible.
Type 'Event' is missing the following properties from type 'KeyboardEvent': altKey, charCode, code, ctrlKey, and 17 more.
The code still runs once transipiled. I would just love some insight into why this is the behavior and a more type safe solution.
这是我的 tsconfig
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"skipLibCheck": true
},
"include": ["src"]
}
如果有人有兴趣拉下 repo 并亲自查看。做我的客人。