fable-import icon indicating copy to clipboard operation
fable-import copied to clipboard

Passing arguments in Electron ipcRenderer/ipcMain

Open dough654 opened this issue 6 years ago • 3 comments

I apologize if the solution to my issue is simple, as I'm still learning Fable (and F# actually).

I'm trying to use the Electron ipcRenderer and ipcMain for inter/process communication (like I normally would in regular electron development). In my renderer I have something like this:

electron.ipcRenderer.send("Hello", ["World"])

Then in my Main.fs, I set up a listener:

electron.ipcMain.on("Hello", unbox(fun x -> printfn "Hello %A" x)) |> ignore

And when I execute, I get the text Hello [object Object] (which I recognize very well from Javascript development.)

The type signature of of the 'send' function is (channel: string *, args: obj []) -> unit

So if i'm reading that correctly, the send function requires a string to representing the channel name, and arguments which is a list of Objects?

So my question is, how can I enforce a type when sending arguments through ipcRenderer send and receive that same type in my callback function in ipcMain?

Also, is there any documentation for these import APIs? I was not able to find any.

dough654 avatar Jan 29 '19 14:01 dough654

I don't think you can enforce the type of the sent arguments and retrieved arguments.

The reason, being sometimes your send function will want to send string, another time int, or MyCustomType. This is why it's mapped to obj so you can pass any type to it.

About the [object Object], if I would be in this situation I would try to print x using JS.console.log(x) which doesn't try to format as printfn do and you will be able to see what you received in response.

From there, you will either be able to use x and retrieve the value or identify a problem in the binding.

MangelMaxime avatar Jan 29 '19 15:01 MangelMaxime

@MangelMaxime Thanks for the suggestion. I'll give it a try. Seems like some type binding would have to take place at some point in order to use x in any meaningful way on the ipcMain side of things. I'll try the JS.Console.log and see if I get any insights from that.

dough654 avatar Jan 30 '19 14:01 dough654

A solution to give some type information would be to have something like:

type IpcRenderer =
    abstract send<'T> : channel: string * args: 'T [] -> unit
    abstract on<'T> : channel: string * ('T [] -> unit) -> unit

let ipcRenderer = Unchecked.defaultof<IpcRenderer>

ipcRenderer.send<int>("channel1", [| 1; 2; 3 |])

ipcRenderer.on<int>("channel1", (fun x -> ()))

But the 'T type from send and on are not related to the type system information. It would still be the job of the developer to be sure to set 'T to the same type for the same channel. We can't make a strong relationship between send<'T> and on<'T> because depending on the channel the argument type will not be the same.

MangelMaxime avatar Jan 30 '19 14:01 MangelMaxime