javascript 类型'(e:"自定义事件)=>void"不能赋给类型为"EventListenerOrEventListenerObject"的参数

kxkpmulp  于 2023-01-04  发布在  Java
关注(0)|答案(6)|浏览(651)

我有这个自定义事件设置,它可以与TypeScript 2.5.3一起使用,但是当我更新到2.6.1时,我收到一个错误

window.addEventListener('OnRewards', (e: CustomEvent) => {
    // my code here
})

[ts]类型'(e:"自定义事件)=〉void"不能赋给类型为"EventListenerOrEventListenerObject"的参数。
类型"(e:自定义事件)=〉void"不能赋给类型"EventListenerObject"。
类型"(e:)"中缺少属性"handleEvent"自定义事件)=〉无效"。
我不太确定该怎么做才能解决这个问题。

nxagd54h

nxagd54h1#

这是由于TypeScript v2.6中添加的--strictFunctionTypes编译器标志的行为所致。(e: CustomEvent) => void类型的函数不再被视为EventListener的有效示例,EventListener采用Event参数,而不是CustomEvent参数。
所以解决这个问题的一个方法是关闭--strictFunctionTypes
另一种方法是传入一个函数,该函数接受一个Event,然后通过一个类型保护将范围缩小到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 
})

第三种方法是使用addEventListener()的另一个重载:

addEventListener<K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, useCapture?: boolean): void;

如果type参数是已知事件类型(K extends keyof WindowEventMap)的名称,如"onclick",则listener函数将期望其参数为该缩小的事件类型(WindowEventMap[K])。问题是"OnRewards"不是已知事件类型...除非您使用declaration merging来 * 使 * 它已知:

// merge into WindowEventMap
interface WindowEventMap {
    OnRewards: CustomEvent
}

或者,如果你在一个模块中(任何包含export的模块),使用全局扩展:

// merge into WindowEventMap
declare global {
  interface WindowEventMap {
    OnRewards: CustomEvent
  }
}

然后像以前一样使用您的代码:

// no error!
window.addEventListener('OnRewards', (e: CustomEvent) => {
    // my code here
})

所以,这些就是你的选择。你想选择哪一个取决于你。希望这对你有帮助;祝你好运!

xytpbqjk

xytpbqjk2#

jcalz's excellent answer的基础上,您还可以使用类型Assert来简化:

window.addEventListener('OnRewards', (e: Event) => {
    const detail = (<CustomEvent>e).detail;
    ...
});
cbeh67ev

cbeh67ev3#

您还可以选择:

window.addEventListener('OnRewards', (e: CustomEvent) => {
    // your code here
} as (e: Event) => void)
yfwxisqw

yfwxisqw4#

我根据@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');
    }
  }
});
yh2wf1be

yh2wf1be5#

是的,另一种满足编译器的方法是强制转换事件对象,例如yourFuctionName(e: Event){ const event = e as CustomEvent <SegmentChangeEventDetail>; console.log(event.detail)}

3hvapo4f

3hvapo4f6#

我在“click”事件上遇到了这个问题,这是一个意外的事件,因为它是一个本机事件,结果你不能只使用内联的document.querySelector,因为推断的类型是Element | null,而不是HTMLElement | null,所以你必须将它声明为一个HTMLElement,这意味着它失败了:

const ele = document.querySelector('#ele');
ele?.addEventListener('click', (event: MouseEvent) => {
   // ...
});

但是当您将其声明为HTMLElement时,它可以正常工作:

const ele = document.querySelector('#ele') as HTMLElement | null;
ele?.addEventListener('click', (event: MouseEvent) => {
    // ...
});

我知道这个问题是关于自定义事件的,但这是在“单击”事件上搜索相同错误时的第一个结果。

相关问题