Type Inference
One of xNet’s key design goals is end-to-end type safety: you define a schema once and TypeScript carries those types all the way through to your React hooks. No manual type annotations, no as casts, no runtime surprises.
How It Works
Section titled “How It Works”The type inference pipeline has three stages:
-
defineSchemacaptures the property builder functions you pass in and preserves their types as a generic parameter. Each builder (liketext(),number(),relation()) returns a typed descriptor that encodes the property’s value type, default, and cardinality. -
InferCreateProps<S>maps over the schema’s property descriptors to produce the type you pass tocreateNode(). Required properties (no default) become required fields; optional properties (with defaults) become optional fields. This is the “write” side of the type. -
FlatNode<S>merges the automatic system fields (id,schemaId,createdAt,updatedAt,createdBy,updatedBy) with the inferred property types to produce the “read” side. These system fields are managed by the store — you don’t define them in your schema. This is what you get back fromuseQueryanduseNode.
From Schema to Hook
Section titled “From Schema to Hook”// 1. Define schema — types are captured hereconst Task = defineSchema('task', { title: text(), done: boolean({ default: false }), assignee: person()})
// 2. Create — TypeScript knows title is required, done is optionalmutate.create('task', { title: 'Ship it' }) // ✅mutate.create('task', {}) // ❌ missing title
// 3. Read — TypeScript knows the full shapeconst tasks = useQuery(Task)tasks[0].title // stringtasks[0].done // booleantasks[0].id // string (from base fields)Extending the Type System
Section titled “Extending the Type System”Because schemas are plain objects with typed descriptors, you can compose them, create utility types around them, and build higher-level abstractions without losing type information. The property builder pattern ensures that new property types automatically flow through InferCreateProps and FlatNode without any changes to the inference machinery.
If you’re building a custom property type, implement the PropertyBuilder interface and the inference pipeline will pick it up automatically.