为什么我在使用索引签名时会丢失事件的类型推断?

问题描述 投票:0回答:0

基于传递给

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 并亲自查看。做我的客人。

typescript dom-events
© www.soinside.com 2019 - 2024. All rights reserved.