【问题标题】:Typescript keyboard event : argument of type 'Event' is not assignable to parameter of type 'KeyboardEvent'打字稿键盘事件:“事件”类型的参数不可分配给“键盘事件”类型的参数
【发布时间】:2018-04-25 23:26:07
【问题描述】:

即使代码运行完美,我也有以下错误:

"TS2345: Argument of type 'Event' is not assignable to parameter of type 'KeyboardEvent'.
  Property 'altKey' is missing in type 'Event'." 

// In a Class

public listenTo = (window: Window) => {
  ['keydown', 'keyup'].forEach(eventName => {
     window.addEventListener(eventName, e => {
       this.handleEvent(e); // <- error here
     });
   });
}

public handleEvent = (event: KeyboardEvent) => {
    const { key } = event;
    //...
}

我尝试将事件类型定义为 KeyboardEvent,但出现以下错误:

 window.addEventListener(eventName, (e:KeyboardEvent) => {
           this.handleEvent(e); // <- error here
         });


 TS2345: Argument of type '(event: KeyboardEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
  Type '(event: KeyboardEvent) => void' is not assignable to type 'EventListenerObject'.
 Property 'handleEvent' is missing in type '(event: KeyboardEvent) => void'.

有没有办法通过或解决问题?

【问题讨论】:

    标签: javascript typescript casting type-conversion


    【解决方案1】:

    字符串'keyup''keydown' 是已知的字符串文字类型。但是,除非它们是 const,否则代码中的字符串不是用于检查已知字符串文字类型的候选者。只需让你的保持不变:

    public listenTo = (window: Window) => {
      ['keydown' as const, 'keyup' as const].forEach(eventName => {
         window.addEventListener(eventName, e => {
           this.handleEvent(e);
         });
       });
    }
    

    public listenTo = (window: Window) => {
      (['keydown', 'keyup'] as const).forEach(eventName => {
         window.addEventListener(eventName, e => {
           this.handleEvent(e);
         });
       });
    }
    

    取决于你的口味。

    【讨论】:

      【解决方案2】:

      TypeScript 在这里无法实现完整的飞跃,因为它只知道事件名称将是一个字符串,因此使用最通用的事件类型。

      下面的示例转换为一个独立运行的示例 - 所以我已经将一些东西“从课堂上”用于演示......

      虽然字符串是keydownkeyup,但您可以保证类型安全,并否决编译器:

      let listenTo = (window: Window) => {
        ['keydown', 'keyup'].forEach(eventName => {
           window.addEventListener(eventName, e => {
             handleEvent(<any>e);
           });
         });
      }
      
      let handleEvent = (event: KeyboardEvent) => {
          const { key } = event;
          //...
      }
      

      如果将其他字符串添加到您的事件名称数组中,这将失败。

      由于专门的签名,直接使用字符串时可以使用完整的类型安全性:

        window.addEventListener('keydown', e => {
           handleEvent(e); // e is KeyboardEvent
        });
      

      所以你可以更强烈地键入你的数组以获得正确的类型:

      type KeyboardEventNames = 'keydown' | 'keyup';
      
      let listenTo = (window: Window) => {
        const eventNames: KeyboardEventNames[] = ['keydown', 'keyup']; 
        eventNames.forEach(eventName => {
           window.addEventListener(eventName, e => {
             handleEvent(e);
           });
        });
      }
      
      let handleEvent = (event: KeyboardEvent) => {
          const { key } = event;
          //...
      }
      

      在最后一个示例中,我们将数组中元素的类型限制为仅键盘事件名称,因此编译器现在知道它不仅仅处理任何旧字符串,并且可以推断事件类型。

      【讨论】:

        猜你喜欢
        • 2021-05-18
        • 2021-10-15
        • 2021-06-30
        • 2021-05-17
        • 2022-07-08
        • 2020-07-19
        • 1970-01-01
        • 1970-01-01
        • 2020-11-05
        相关资源
        最近更新 更多