Last active
September 16, 2018 14:26
-
-
Save OliverJAsh/9619a49d345c334e5f68473565457167 to your computer and use it in GitHub Desktop.
TypeScript tagged union with generic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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