-
Notifications
You must be signed in to change notification settings - Fork 873
Description
Bug Summary
The TypeScript code generator (spacetime generate --lang typescript) for Rust modules sometimes emits direct property references to type objects in types.ts that are defined later in the file. This causes a ReferenceError: Cannot access '<Type>' before initialization at runtime.
The codegen already handles this for some types by using lazy get accessors, but it misses certain cases, producing a mix of lazy and eager references in the same object literal.
Error
types.ts:733 Uncaught ReferenceError: Cannot access 'TileOverride' before initialization
at types.ts:733:39
Version
- SpacetimeDB CLI:
2.0.3 - Module language: Rust
- Client: TypeScript (React via
spacetimedb/react)
Root Cause
In the generated types.ts, type objects are defined in a specific order. When type A contains a field referencing type B, and B is defined after A, the reference must be deferred.
The codegen already uses lazy get accessors for some fields:
// Correct — lazy evaluation, works with forward references
get terrainProfile() {
return __t.option(TerrainProfile);
},
get placementConstraints() {
return __t.option(PlacementConstraints);
},But for other fields in the same object, it emits eager references:
// Broken — eager evaluation, TileOverride not yet defined at this point
tileOverrides: __t.option(__t.array(TileOverride)),The inconsistency suggests the codegen has logic to detect forward references and emit get accessors, but that logic doesn't cover all cases — possibly missing when the type is wrapped in __t.array() or __t.option(__t.array(...)).
Reproduction
- Create a Rust SpacetimeDB module with two types where type
Ahas aVec<B>field andBis defined in a separate file that sorts alphabetically afterA - Run
spacetime generate --lang typescript --out-dir ./bindings --module-path ./server - The generated
types.tswill contain an eager reference toBinsideA's definition - Import
types.tsin a client → runtime crash
Workaround
Manually edit the generated types.ts to wrap the offending line in a lazy getter:
// Before (broken):
tileOverrides: __t.option(__t.array(TileOverride)),
// After (fixed):
get tileOverrides() {
return __t.option(__t.array(TileOverride));
},This must be reapplied after every spacetime generate run.
Suggested Fix
The codegen should use lazy get accessors for all fields that reference other user-defined types, not just some. Alternatively, topologically sort type definitions so that referenced types are always emitted before their dependents.
Environment
- Windows 11 Pro
- SpacetimeDB 2.0.3