Passing arguments in Electron ipcRenderer/ipcMain
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.
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 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.
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.