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?