Hi. I want to use {..}
as a field type with @deriving(abstract)
. But when I try to define it like so:
@deriving(abstract)
type config = {x: {..}}
I get this error: “A type variable is unbound in this type declaration. In field x: {…} as 'a the variable 'a is unbound”
I came up with this workaround:
type x
external makeX: {..} => x = "%identity"
@deriving(abstract)
type config = {x: x}
let myConfig = config(~x=makeX({"foo": 1}))
But is there a better way?
tsnobip
February 25, 2022, 9:43am
2
This is because {..}
is indeed polymorphic as the compiler complains.
Try this instead:
@deriving(abstract)
type config<'a> = {x: {..} as 'a}
3 Likes
tsnobip
February 25, 2022, 9:44am
3
The other question would be why you need @derving(abstract)
though
Thanks I’ll try this.
I’m writing bindings for node-postgres
and use deriving for the config object that has a lot of optional fields: https://node-postgres.com/api/client
The {..}
is for the ssl
field, BTW.
Is there something better than @derving(abstract)
for this, than would not force users to explicitly set all optional fields to something like None
?
config<'a>
doesn’t quite work, because I also want this field to be optional. I get a error with this code:
@deriving(abstract)
type config<'a> = {@optional x: {..} as 'a}
// Works
let myConfig1 = config(~x={"foo": "bar"})
// Error:
// This expression's type contains type variables that can't be generalized:
// config<{_..}>
let myConfig2 = config()
tsnobip
February 25, 2022, 12:31pm
6
yes you can use @obj
like this:
type config
@obj external config: (~x: {..}=?, unit) => config = ""
Yes I think in this case you have to annotate your value:
let config: config<{.}> = config()
BTW we have a pretty complete set of bindings for Node-Postgres at work, it’s customized to our needs so not something we could really publish as is, but if you’re interested, it could be a good base for your own bindings. I’ll ask if we can share them.
3 Likes
@obj
seem to work great so far, I don’t even need the type variable. Thank you!
@obj
external config: (~x: {..}=?, unit) => _ = ""
let myConfig1 = config(())
let myConfig2 = config(~x={"foo": 1}, ())
Yes, if you could share your bindings that would probably help me a lot. Would appreciate that!
tsnobip
February 25, 2022, 1:39pm
8
Sorry yeah I’ll edit my solution, you’re supposed to keep your type opaque so no need for a type variable, indeed.
1 Like
spyder
February 28, 2022, 1:04am
9
There are changes coming in ReScript 10 that will make this sort of thing easier
Hi, I polished the implementation a little bit, the feature is close to be finalized.
So this new feature would be opt-in by using an attribute called @obj. For types like this:
@obj
type r = {
x : int ,
y : option <int>
}
let v0 = { x : 3 }
let v1 = { x : 3 , y : None}
generated JS would be:
var v0 = { x : 3 }
var v1 = { x : 3 }
The idea is that for objects annotated with obj, you don’t care about its performance in general, it is used in config patterns with lots of optionals.
Let …
4 Likes