Hey all, I have perhaps an interesting case where I’m writing a library that, at the base layer, should be very flexible in terms of what types are supported. The end user will almost never touch this base layer, they will use specialized APIs a few layers higher that formally express concrete type expectations. But, I’m struggling to express my “generic” layer in the first place.
To start, I have a very simple object which should look something like:
type t = {
"type": string | NicelyTypedFunction,
"props": Js.object,
}
Forgive my pseudo-syntax, I don’t yet know how to actually write this in Rescript. The part that I’m struggling with is that this “props” field on the object needs to be dynamic; at this layer in the codebase, any javascript value can come through that props object (not unlike React as it tries to marshal props to the DOM) and I don’t know how to express that detail in the formal Rescript type system.
Can anybody help me point in the right direction? Thanks
Yep, ultimately “props” holds this collection of key/value pairs that will be passed on to an external/underlying “host” (here again, much like React and the DOM). The framework that I’m working on will sit atop several different “hosts” and each one may expect different sets of key/value props from the upper layer/framework. Ultimately it’s these hosts which determine what key/value props are expected and supported but there’s no way for the higher level framework to know what host it’s running against so it must remain totally generic from a type perspective
You can use abstract type for props. This way you do not define it’s structure in any way, but can cast anything you want to it.
type props // abstract type
type objectWithProps = {
kind: string,
props: props
}
type a = {
id: string,
count: int
}
external aAsProps : a => props = "%identity" // casting
let x = {
kind: "a",
props: aAsProps({id: "", count: 0})
}
external asPropsType : 'a => props = "%identity" // casting
parameterizes this asPropsType function as taking a generic 'a and producing a props type? That is, generically maps arbitrary input to the props type?
Another small question here– so I’m exploring this solution with genType and locally it seems like the following TSX file is produced from compiling the playground:
Now, as far as I understand the currying, this is a great output. My only confusion is that it seems that the seq and createNode functions produce an output which has the same structure as the node type, why are those return types not just node?
Ah ok I’ve answered my own second question there– I believe in the playground link I shared I was returning an Object from createNode but the type definition of node was a Record. I’ve added quotes to the keys in the typedef of node and now everything seems to work neatly.
your version of asPropsType would work too, but for me it’s too generic.
You said that there will be several “hosts” and each of them will have its own variant of props. Assuming props for every host will defined as a record, I suggest to have converter function for every record. Something like:
The downside of this is it will be harder to hold a collection that contains multiple nodes with different props types, but an identity external can help with that.