Recursive Types
If you want an object type to be able to contain one of itself (recursion), then you have to start using keyed types. The basic pattern is this:
/** * Wrapping a schema with a 'bin.keyed' call allows the inner code to * use a reference to the type we're currently creating, instead * of the type itself. * * The reference variable 'Recursive' doesn't have to be called * the same as the actual variable we're storing the schema in, * but it's a neat trick that makes the schema code more readable. * * The 'recursive-key' has to uniquely identify this type in this tree. * There may be other distinct types using the same key, as long as they do * not interact with each other (one doesn't contain the other). * This is because references are resolved recursively once the method * passed as the 2nd argument to 'keyed' returns the schema. */const Recursive = bin.keyed('recursive-key', (Recursive) => bin.object({ value: bin.i32, next: bin.optional(Recursive), }));
Recursive types alongside generics
import bin from 'typed-binary';
const Expression = bin.keyed('expression', (Expression) => bin.generic( {}, { multiply: bin.object({ a: Expression, b: Expression, }), negate: bin.object({ inner: Expression, }), int_literal: bin.object({ value: bin.i32, }), } ));
type Expression = bin.Parsed<typeof Expression>;
const expr: Expression = { type: 'multiply', a: { type: 'negate', inner: { type: 'int_literal', value: 15, }, }, b: { type: 'int_literal', value: 2, },};