Bs.deriving bs.optional removed

In the past I used to create JS objects without having to express None for all of my optional values. Is there a way to do that in rescript now that bs.deriving and bs.optional are gone?

Is it really gone? Only from the docs if I’m not mistaken, but it should definitely be there because the use case is obvious for objects with many optional fields.

@bs.deriving abstract and @bs.optional are both still present in bs-platform 8.2. :thinking:

For what it’s worth, though, you can achieve the same output with @bs.obj. The only difference is that ReScript won’t generate accessor functions to access the object properties.

type t
@bs.obj external make: (~a: int, ~b: int=?, unit) => t = ""

let a = make(~a=1, ()) // outputs {a: 1}

I can’t speak for the ReScript team, but it seems like they may be encouraging using ReScript Object syntax more:

let a = { "a" : 1}
let b = {"a": 1, "b": 2}

Well you have the same issue with optional fields though, for config objects for example

Hello and welcome!

Yeah, it’s usually recommended to use record and object over this particular feature, but this one does have its use-cases. For example, sometime the lack of fields themselves is important for JS interop; some APIs explicitly (and annoyingly) check for said absence of fields. So having fixed fields + undefined for their values doesn’t always work.

bs.deriving abstract is actually just convenience codegen for bs.obj + bs.get/set under the hood.

Thanks for all the replies. My particular use case was having to create a JS object with a bunch of properties either not set or set to undefined.
So I went with the documented record type, like this:

type t = {
  method: string,
  body: option<string>
};

Only after having created the post I noticed I could do something like

let makeTObject = (~method, ~body=?, ()) => {method,body};

And that works beautifully. Now, say I have not just body but a large list of optional properties, in that case the recommended alternative (in case I don’t want to write the make function myself) would be to use bs.deriving, correct?

yes @mciparelli then you could use bs.deriving abstract to generate the make function, don’t forget to annotate the optional fields with @bs.optional instead of typing them as options.

@bs.deriving(abstract)
type t = {
  method: string,
  @bs.optional body: string
}

But then your type t won’t be a record anymore, you won’t be able to pattern match on it or create it as a normal record. This is usually not an issue when creating an object meant to be consumed in JS. In that case, you could more simply use bs.obj like this:

@bs.obj external makeTObject: (~method: string, ~body:string=?, unit) => _ = ""

Notice that you could here model method as a string literal for better type safety.

yes, there are still definitely use cases for bs.obj, that should be in the docs I think.
I would trade it for https://github.com/rescript-lang/rescript-compiler/issues/4312 any time of the day though :slight_smile: That would allow to easily write 0-cost bindings nicer than the original JS function :astonished:

2 Likes