I’m trying to create bindings for @slack/bolt and I’m having some trouble creating a Module that feels natural in ReScript/ReasonML. In general, I have a couple exports I need to create bindings for that do something like this (in JS)
import { Foo, Bar } from '@slack/bolt'
const foo = new Foo({ param: 'string' })
foo.method1()
foo.property1
foo.method2()
I’ve tried something like this but it’s not behaving how I would like…
module ExpressReceiver = {
type t
type app: Express.App.t
@module("@slack/bolt") @new
external make: (~signingSecret: string) => t = "ExpressReceiver"
}
I’m currently doing this right now but was wondering if there’s a way to just put the instance methods (for lack of a better term) on the module itself
There is, but I recommend not doing that. Properties are fine - methods are more flexible when they’re done in a static style that uses @send to convert them to instanced at runtime.
Can you show a specific example of what you need in terms of JS code? Your first JS code is talking about ‘Foo’ and ‘Bar’ and then your ReScript code is talking about ‘ExpressReceiver’, so I’m not being able to understand how they’re related.
If we assume for a second that the ‘Foo’/‘Bar’ example code is the JS you need to output from ReScript, then you could bind it like this:
// Bolt.res
module Foo = {
type t
type options = {param: string}
@module("@slack/bolt") @new external make: options => t = "Foo"
@send external method1: t => unit = "method1"
@get external property1: t => int = "property1" // e.g.
@send external method2: t => unit = "method2"
}
let foo1 = Foo.make({param: "string"})
Foo.method1(foo1)
let x = Foo.property1(foo1)
Foo.method2(foo1)
Couple of reasons. For a single function call I usually don’t use pipes. And I wanted to make it simple and obvious that the binding is giving us a function.
Ah, thank you! I’m reading up on send now and I love the trick of using the pipe first operator. I was passing in the instance, which was working as well. Thanks so much for the reply and code snippet!
I can appreciate that at a technical level, but when teaching JS programers telling them that foo->method compiles to foo.method (which isn’t always true but my app works with a ton of bindings) they find it much easier to get started.
Using pipe with a single function call is indeed a grey area.
However, the new editor integration finally lets us achieve one important thing we’ve always wanted: -> pipe autocompletion. So it’s understandable that you wanna write myValue->methodSomewhere. Or not. Doesn’t matter too much either way. Just keep things readable.
I guess I should’ve been more specific - I don’t tend to encourage pipe for methods that take one argument. Once there are multiple arguments it looks a lot more normal.