类型与事件侦听器冲突

Type conflicts with Event Listeners

我正在尝试使用寓言将事件处理程序附加到 DOM 节点:

let handleIntroSubmit (event: Event) = ()

container
    .querySelector("#some-node")
    .addEventListener("click", handleIntroSubmit)

但是失败并出现以下错误:

这个错误让我感到困惑,因为:

查看 Fable.Import.Browser I find EventListenerOrEventListenerObject defined 的来源:

EventListenerOrEventListenerObject =
    U2<EventListener, EventListenerObject>

EventListener defined这样:

EventListener = (Event -> unit)

看看这个定义,我会假设 handleIntroSubmitEventListener 兼容,因此与联合类型 EventListenerOrEventListenerObject 兼容?

然而,令我惊讶的是,我发现它实际上与 EventListener 不兼容,即使它们的签名看起来与我相同。当我尝试以下操作时:

let listener: EventListener = handleIntroSubmit

我收到以下错误:

This expression was expected to have type
    'EventListener'    
but here has type
    ''a -> unit'

这个错误对我来说毫无意义,特别是我不知道 'a 泛型类型来自哪里,尽管我已经为函数 handleIntroSubmit 参数提供了显式类型注释.

理想情况下,我想知道为什么上面的方法不起作用,这里的错误意味着什么以及使用 Fable 添加事件侦听器的best/typesafe(没有拆箱)方法是什么。

Fable 的 gitter 上的相关 discussion

已在 solution provided by Maxime Mangel - relevant fiddle 中解决。

btn.addEventListener("click", !^(Func<_,_>(fun _ -> console.log "clicked2")))

这里有两个不同的问题。

首先, 您链接 only appeared in master two days agoEventListener 的定义。在此之前,定义是 Func<Event, unit>,这是一个 .NET 委托,与 F# 函数 Event -> unit 完全不同。从错误消息中可以看出,您使用的是早期版本的库。

要解决此问题,请像这样重新定义您的函数:

let handleIntroSubmit = Func<Event, unit>( fun e -> () )

这将赋予它 Func<Event, unit> 的类型,这就是 EventListener 的类型(当前)。

其次,即使handleIntroSubmit兼容EventListener,也不代表它也会兼容U2<EventListener, _>。那是完全不同的类型,为什么会兼容?

要从 EventListener 的值生成 U2<EventListener, _> 的值,请使用 first constructor of the U2 union - Case1:

let listener: U2<EventListener, EventListenerObject> = Case1 handleIntroSubmit

当然,每次都写Case1有点乏味。值得庆幸的是,为了处理这种情况,Fable 的核心库提供了 a handy operator !^:

let listener: U2<EventListener, EventListenerObject> = !^handleIntroSubmit