4

我尝试为 socket.io 编写一个绑定。

我在使用不带参数或错误对象 ( ) 的函数时遇到问题(next()在底部的示例代码中Js.Exn.raiseError("ERROR!"))。

我找不到一种方法来定义可以将两种类型的参数作为第一个值的函数签名。

我什至不确定,如果我所要求的内容可以在 rescript 中实现,那么以正确的 rescript 方式解决该问题的任何帮助将不胜感激。

我当前的实现如下所示:

type server
type socket
type next = (. unit) => unit 

@new @module("socket.io") external socketIO: unit => server = "Server"
@send external use: (server, (socket, next) => unit) => unit = "use"
@send external listen: (server, int) => unit = "listen"
@send external on: (server, @string [ #connection(socket => unit) ] ) => unit = "on"

let io = socketIO()

io->use((socket, next) => {
    Js.log("FIRST")
    next(.)
})

io->use((socket, next) => {
    Js.log("SECOND")
    next(.)
})

io->on(#connection(socket => 
    Js.log("CONNECT")
))

io->listen(3000)
4

1 回答 1

2

通常不可能有一个具有可变数量参数的函数,但可以传递其中一个undefined或一个值,在大多数情况下这将是等效的。

一种方法是简单地使用option类型。如果我们重新定义next

type next = (. option<int>) => unit 

我们可以这样使用它

io->use((_socket, next) => {
    next(. None)
    next(. Some(42))
})

这将生成以下 JavaScript:

io.use(function (_socket, next) {
      next(undefined);
      return next(42);
    });

另一种选择可能是使用可选参数,但这似乎不适用于 uncurrying,而且最近出现了 currying 的错误,编译器作者似乎对修复没有兴趣,因此它可能在那里也不起作用,但它可能值得一试:

type next = (~error: int=?, unit) => unit
...
io->use((_socket, next) => {
    next(())
    next(~error=42, ())
})

最后,socket.io ( bs-socket.io )已经存在一些绑定。不幸的是,这些也不能处理这种情况,但它至少可以让你免于重新发明一些轮子。

于 2021-11-20T18:44:49.610 回答