Here’s an example snippet of TypeScript code modeling a Tree type
enum TreeType {
  Node = 0,
  Leaf = 1,
}
interface Tree {
  type: TreeType;
}
interface Node extends Tree {
  type: TreeType.Node;
  left: Tree;
  right: Tree;
  value: string;
}
interface Leaf extends Tree {
  type: TreeType.Leaf;
  value: string;
}
function createTree(): Tree {
  // some code
}
function isNode(v: Tree): v is Node {
  return v.type === TreeType.Node;
}
function isLeaf(v: Tree): v is Leaf {
  return v.type === TreeType.Leaf;
}
How can I write a binding in ReScript code so that I could operate on the Tree type?
@module("tree")
external createTree: unit => tree = ""
I looked at this example Modelling Interfaces in ReScript where the author is using a module type to model the interface, but it doesn’t seem to work with recursive type (maybe it does but I am not sure how, please let me know if I’m wrong with this).
Here’s another approach that I have in mind
@deriving({ jsConverter: newType })
type treeType =
| Node
| Leaf
type rec tree = {
  @as("type") type_: abs_treeType
} and node = {
  @as("type") type_: abs_treeType,
  left: tree,
  right: tree,
  value: string
} and leaf = {
  @as("type") type_: abs_treeType,
  value: string
}
external treeToNode : tree => node = "%identity";
external treeToLeaf : tree => leaf = "%identity";
@module("tree")
external createTree: unit => tree = ""
With this definition, I can do something like this
let t = createTree()
Js.log(t.type_)
switch treeTypeFromJs(t.type_) {
  | Node => {
    let n = treeToNode(t)
    Js.log(n.left)
  }
  | Leaf => {
    let l = treeToLeaf(t)
    Js.log(l.value)
  }
}
which I’m just using the %identity to cast the type from tree to node or leaf, this seems to work (although it is not type safe), but there are two things that I don’t quite like about it.
One thing is that I have the field type_ repeated over 3 of the struct types and value repeated over both node and leaf type and the compiler is not very happy about it, another thing is that three of these types aren’t really associated as if in the code in TypeScript, where Node and Leaf are the subtype of Tree. The latter isn’t much of an issue but the first one is really bugging me. In that case, what could be a better way to model the subtyping/inheritence and the type casting between them?