类型与事件侦听器冲突
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)
看看这个定义,我会假设 handleIntroSubmit
与 EventListener
兼容,因此与联合类型 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 ago 的 EventListener
的定义。在此之前,定义是 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
我正在尝试使用寓言将事件处理程序附加到 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)
看看这个定义,我会假设 handleIntroSubmit
与 EventListener
兼容,因此与联合类型 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 ago 的 EventListener
的定义。在此之前,定义是 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