typescript “(e: CustomEvent) => void”类型的参数不可分配给“EventListenerOrEventListenerObject”类型的参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/47166369/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Argument of type '(e: CustomEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'
提问by Get Off My Lawn
I have this custom event setup, and it works with TypeScript 2.5.3, but when I updated to 2.6.1I get an error
我有这个自定义事件设置,它适用于 TypeScript 2.5.3,但是当我更新到2.6.1我收到一个错误
window.addEventListener('OnRewards', (e: CustomEvent) => {
    // my code here
})
[ts] Argument of type '(e: CustomEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'.
Type '(e: CustomEvent) => void' is not assignable to type 'EventListenerObject'.
Property 'handleEvent' is missing in type '(e: CustomEvent) => void'.
[ts] '(e: CustomEvent) => void' 类型的参数不可分配给 'EventListenerOrEventListenerObject' 类型的参数。
类型 '(e: CustomEvent) => void' 不能分配给类型 'EventListenerObject'。
类型 '(e: CustomEvent) => void' 中缺少属性 'handleEvent'。
I am not exactly sure what to do here to fix this.
我不确定在这里做什么来解决这个问题。
回答by jcalz
This is due to the behavior of the --strictFunctionTypescompiler flag added in TypeScript v2.6.  A function of type (e: CustomEvent) => voidis no longer considered to be a valid instance of EventListener, which takes an Eventparameter, not a CustomEvent.  
这是由于--strictFunctionTypesTypeScript v2.6 中添加的编译器标志的行为。类型的函数(e: CustomEvent) => void不再被视为 的有效实例EventListener,它接受一个Event参数,而不是一个CustomEvent。  
So one way to fix it is to turn off --strictFunctionTypes.
因此,修复它的一种方法是关闭--strictFunctionTypes.
Another way is to pass in a function that takes an Eventand then narrows to CustomEventvia a type guard:
另一种方法是传入一个函数,该函数接受 anEvent然后CustomEvent通过类型保护缩小为:
function isCustomEvent(event: Event): event is CustomEvent {
  return 'detail' in event;
}
window.addEventListener('OnRewards', (e: Event) => {
  if (!isCustomEvent(e))
    throw new Error('not a custom event');
  // e is now narrowed to CustomEvent ...
  // my code here 
})
A third way is to use the other overload of addEventListener():
第三种方法是使用 的其他重载addEventListener():
addEventListener<K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, useCapture?: boolean): void;
If the typeparameter is the name of a known event type (K extends keyof WindowEventMap) like "onclick", then the listenerfunction will expect its parameter to be of that narrowed event type (WindowEventMap[K]).  The problem is that "OnRewards"is not a known event type... unless you use declaration mergingto makeit known:
如果type参数是已知事件类型 ( K extends keyof WindowEventMap)的名称,例如"onclick",则该listener函数将期望其参数属于该缩小的事件类型 ( WindowEventMap[K])。问题是这"OnRewards"不是已知的事件类型……除非您使用声明合并来使其为人所知:
// merge into WindowEventMap
interface WindowEventMap {
    OnRewards: CustomEvent
}
Or, if you're inside a module (anything with exportin it), use global augmentation:
或者,如果您在模块内(其中包含任何export内容),请使用全局增强:
// merge into WindowEventMap
declare global {
  interface WindowEventMap {
    OnRewards: CustomEvent
  }
}
Then use your code as before:
然后像以前一样使用您的代码:
// no error!
window.addEventListener('OnRewards', (e: CustomEvent) => {
    // my code here
})
So, those are your options. Which one you want to choose is up to you. Hope that helps; good luck!
所以,这些是你的选择。你想选择哪一个取决于你。希望有所帮助;祝你好运!
回答by JacobEvelyn
Building off of jcalz's excellent answer, you can also use a type assertionto be a little cleaner:
基于jcalz 的优秀答案,您还可以使用类型断言来更简洁:
window.addEventListener('OnRewards', (e: Event) => {
    const detail = (<CustomEvent>e).detail;
    ...
});
回答by Frederik Krautwald
You also have this option:
你也有这个选项:
window.addEventListener('OnRewards', (e: CustomEvent) => {
    // your code here
} as (e: Event) => void)
回答by Stephen Paul
I created a generic function based off @jcalz's answer
我根据@jcalz 的回答创建了一个通用函数
/**
 * Checks whether an object can be safely cast to its child type
 * @param parent the object to be 'narrowly' cast down to its child type
 * @param checkForProps props which aught to be present on the child type
 */
export function isSubTypeWithProps<P, C extends P>(parent: P, ...checkForProps: (keyof C)[]): parent is C {
  return checkForProps.every(prop => prop in parent);
}
/**
 * Usage example
 */
const el = document.getElementById('test');
el.addEventListener('click', (e: Event) => {
  if (isSubTypeWithProps<Event, MouseEvent>(e, 'which')) {
    if (e.which === 1) { // primary mouse button only ('which' prop is only available on MouseEvent)
      console.log('clicked');
    }
  }
});

