If OCaml allowed an array to have elements of different types, it will be impossible for it to enforce type safety. Imagine a printItem
function that takes a value of item
- how does it tell whether subItem
is a string, so it can apply print_string
on it, or whether it is a bool so it can apply print_bool
on it?
The type-safe solution is to explicitly tell the compiler that you expect the value to take on one among different possible types, and that is done through variants, as in your second example. There is no getting around it. However, you can simplify the type definition and any code that relies on that type with this:
type item = {
name: string,
subItem: option(string),
};
let print_item = t =>
Js.log(
t.name
++ " - "
++ (
switch (t.subItem) {
| Some(subItemName) => subItemName
| None => "(there is no subitem)"
}
),
);
print_item({name: "A", subItem: None});
print_item({name: "B", subItem: Some("x")});
Last I checked [@bs.deriving abstract]
didn’t work for variant constructors that had values inside them, and so to send this to Javascript, you’ll have to write a JSON serializer explicitly. The following code uses the bs-json
library:
let toJson = t =>
Json.Encode.object_([
("name", t.name |> Json.Encode.string),
(
"subItem",
switch (t.subItem) {
| Some(subItemName) => subItemName |> Json.Encode.string
| None => false |> Json.Encode.bool
},
),
]);
This creates a Javascript object whose values can be of different types, and you can use the object directly in your Javascript code. If you want to serialize it to text you can use Js.Json.stringify
, send it over a network, and parse it with JSON.parse
on the other side.