Skip to content

Instantly share code, notes, and snippets.

@OliverJAsh
Last active September 16, 2018 14:26
Show Gist options
  • Save OliverJAsh/9619a49d345c334e5f68473565457167 to your computer and use it in GitHub Desktop.
Save OliverJAsh/9619a49d345c334e5f68473565457167 to your computer and use it in GitHub Desktop.
TypeScript tagged union with generic
export type Node<P> = {
value: P;
children: Array<Tree<P>>;
};
type Leaf<P> = {
value: P;
};
enum TreeTag {
Node = 'Node',
Leaf = 'Leaf',
}
type TreeRecord<P> = {
[TreeTag.Node]: Node<P>;
[TreeTag.Leaf]: Leaf<P>;
};
type TreeTaggedRecord<P> = {
[Tag in TreeTag]: { tag: Tag; value: TreeRecord<P>[Tag] }
};
type Tree<P> = TreeTaggedRecord<P>[TreeTag];
// Constructors
const node = <P>(value: Node<P>): Tree<P> => ({
tag: TreeTag.Node,
value,
});
const leaf = <P>(value: Leaf<P>): Tree<P> => ({
tag: TreeTag.Leaf,
value,
});
type TreeTaggedNode<P> = TreeTaggedRecord<P>['Node'];
type TreeTaggedLeaf<P> = TreeTaggedRecord<P>['Leaf'];
// Predicates
const checkIsNode = <P>(tree: Tree<P>): tree is TreeTaggedNode<P> => tree.tag === TreeTag.Node;
const checkIsLeaf = <P>(tree: Tree<P>): tree is TreeTaggedLeaf<P> => tree.tag === TreeTag.Leaf;
// Example
const tree = node({ value: 'foo', children: [leaf({ value: 'bar' })] });
const matchExample = <P>(tree: Tree<P>) => {
switch (tree.tag) {
case TreeTag.Node:
return tree.value.value;
case TreeTag.Leaf:
return tree.value.value;
}
};
console.log(matchExample(tree));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment