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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:01:18  来源:igfitidea点击:

Argument of type '(e: CustomEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'

javascripttypescript

提问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');
    }
  }
});