01 · Problem
What is it for?
A binary format needs fixed widths, byte order and bounds; JavaScript objects do not provide a wire layout.
02 · Mental model
How should you think about it?
A schema is a cursor program: each field consumes a documented number of bytes in a deterministic order.
Round-trips fixed-layout unsigned integers, booleans, UTF-8 strings and arrays. This is a versionless fixed-layout format. Schema ordering and migration must be agreed by both endpoints; decorators use the legacy TypeScript contract.
03 · Control flow
What happens in which order?
- Define field order and byte widths.
- Allocate the required buffer.
- Write fields and advance the cursor.
- Read using the same schema and bounds.
04 · Building blocks
The important contracts
BinarySerializer.serialize / deserializeRead and write explicit fixed-layout schemas.Serializable / AsNumber / AsBoolean / AsString / AsArray / SerializedDeclare legacy decorator schemas, including nested serializable fields.05 · Build it yourself
Implement a small core
Start with this small independent implementation, then use the steps below to make its contract explicit.
- Define field order and byte widths.
- Allocate the required buffer.
- Write fields and advance the cursor.
- Read using the same schema and bounds.
type Decoded<T> = { value: T; offset: number };
interface Codec<T> {
size(value: T): number;
encode(view: DataView, offset: number, value: T): number;
decode(view: DataView, offset: number): Decoded<T>;
}
const u32: Codec<number> = {
size: () => 4,
encode: (view, at, value) => (view.setUint32(at, value, true), at + 4),
decode: (view, at) => ({ value: view.getUint32(at, true), offset: at + 4 }),
};06 · Verify
What should you test?
- Assert exact bytes as well as round-trip values.
- Test truncated buffers and oversized strings.
- Check nested schemas and UTF-8 byte boundaries.
Try it yourself
Turn the first verification claim into a failing test, implement the smallest fix, then add a boundary case.
Assert exact bytes as well as round-trip values.
Compare your approach
Your check should fail when the stated invariant is deliberately broken, and pass again after the fix. Keep setup deterministic and assert an observable result.
07 · Limits
Trade-offs and failure modes
- Numbers currently use unsigned 32-bit little-endian encoding.
- Schema evolution requires an explicit version.
- Decorator insertion order alone is a fragile wire contract.
This is a versionless fixed-layout format. Schema ordering and migration must be agreed by both endpoints; decorators use the legacy TypeScript contract.
08 · Keep exploring
Source code and related ideas
yarn tsx packages/binary-serializer/examples/basic.ts