Structs
Define structured data types with RStruct and field().
Defining a Struct
Use RStruct to define a schema with named fields:
// Demonstrates: Defining struct schemas with RStruct and field()
import { RStruct, RString, RU32, RBool, field } from "@grounds/schema";
import type { Static } from "@sinclair/typebox";
// Define a User schema
// Each field has a numeric ID (for wire format) and a type
const UserSchema = RStruct({
id: field(0, RU32()),
name: field(1, RString()),
active: field(2, RBool()),
});
// Static<typeof Schema> extracts the TypeScript type
type User = Static<typeof UserSchema>;
// TypeScript now knows the exact shape
const user: User = {
id: 12345,
name: "Alice",
active: true,
};
console.log("User schema defined successfully");
console.log("User object:", user);
console.log("TypeScript infers: { id: number, name: string, active: boolean }");
Field IDs
Each field has a numeric ID used in the wire format. Field IDs:
- Must be unique within a struct
- Are used for encoding (not the field name)
- Allow schema evolution (add new IDs, deprecate old ones)
Type Inference
Use Static<typeof Schema> to extract the TypeScript type:
import type { Static } from "@sinclair/typebox";
type User = Static<typeof UserSchema>;
// { id: number; name: string; active: boolean }
Available Field Types
| Schema Type | TypeScript Type | Relish Type |
|---|---|---|
RString() | string | String |
RBool() | boolean | Bool |
RU8() - RU128() | number / bigint | u8 - u128 |
RI8() - RI128() | number / bigint | i8 - i128 |
RF32(), RF64() | number | f32, f64 |
RTimestamp() | DateTime | Timestamp |
ROptional(T) | T | null | Optional wrapper |
RArray(T) | Array<T> | Array |
Next Steps
Learn about Enums for tagged unions, or Codecs for serialization.