打字稿键盘事件:“事件”类型的参数不可分配给“键盘事件”类型的参数

Posted

技术标签:

【中文标题】打字稿键盘事件:“事件”类型的参数不可分配给“键盘事件”类型的参数【英文标题】: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'.

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

【问题讨论】:

【参考方案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;
    //...

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

【讨论】:

以上是关于打字稿键盘事件:“事件”类型的参数不可分配给“键盘事件”类型的参数的主要内容,如果未能解决你的问题,请参考以下文章

AWS CDK,打字稿-“this”类型的参数不可分配给“Construct”类型的参数

打字稿:如何键入 Ramda R.prop(key) T' 不可分配给类型为 '(s: ) => 的参数

expressjs:打字稿:“typeof <express.Router>”类型的参数不可分配给“RequestHandlerParams”类型的参数

打字稿错误 TS2345 错误:TS2345:“缓冲区”类型的参数不可分配给“字符串”类型的参数

打字稿:类型'null'不可分配给类型错误

打字稿 - 字符串'不可分配给类型'FC