Structs
Structs (structures) let you create custom composite types with named fields. They’re ideal for grouping related data together.
Source: User-defined types
Declaring a Struct
Use the struct keyword followed by the type name and field definitions:
struct Player {
address: Bytes<32>,
score: Uint<64>,
isActive: Boolean
}
Fields are separated by commas (or semicolons). A trailing separator is allowed but not required.
Source: User-defined types
Creating Struct Values
Create a struct value using the struct name followed by field values in braces:
struct Player {
address: Bytes<32>,
score: Uint<64>,
isActive: Boolean
}
export pure circuit createPlayers(ownerKey: Bytes<32>): Player {
// Named fields (recommended for clarity)
const player = Player {
address: ownerKey,
score: 0,
isActive: true
};
// Positional fields (order must match declaration)
const player2 = Player { ownerKey, 0, true };
// Mixed: positional first, then named
const player3 = Player { ownerKey, 0, isActive: true };
return player;
}
Source: Structure creation
Accessing Fields
Use dot notation to access struct fields:
struct Player {
address: Bytes<32>,
score: Uint<64>,
isActive: Boolean
}
export pure circuit readFields(ownerKey: Bytes<32>): Boolean {
const player = Player { address: ownerKey, score: 100, isActive: true };
const addr = player.address; // Bytes<32>
const points = player.score; // Uint<64>
const active = player.isActive; // Boolean
return active;
}
Source: Element and member access expressions
Default Values
The default value of a struct has all fields set to their type’s default:
struct Player {
address: Bytes<32>,
score: Uint<64>,
isActive: Boolean
}
export pure circuit emptyPlayer(): Player {
const empty = default<Player>;
// Equivalent to: Player { address: default<Bytes<32>>, score: 0, isActive: false }
return empty;
}
Source: Default values
Nested Structs
Structs can contain other structs. Use chained dot notation to access nested fields:
struct Coordinate {
x: Field,
y: Field
}
struct Rectangle {
topLeft: Coordinate,
bottomRight: Coordinate
}
export pure circuit area(rect: Rectangle): Field {
const width = rect.bottomRight.x - rect.topLeft.x;
const height = rect.bottomRight.y - rect.topLeft.y;
return width * height;
}
Source: User-defined types
Structs in Maps
Structs can be used as values in Map ledger types:
struct UserData {
balance: Uint<64>,
lastAction: Uint<64>,
isVerified: Boolean
}
export ledger users: Map<Bytes<32>, UserData>;
Source: Nested state types in Map
Exporting Structs
To use a struct from TypeScript, export it:
export struct Player {
address: Bytes<32>,
score: Uint<64>,
isActive: Boolean
}
Source: Top-level exports
TypeScript Representation
Exported structs map to TypeScript objects with the same field names:
// Compact
export struct Player {
address: Bytes<32>,
score: Uint<64>,
isActive: Boolean
}
// TypeScript representation
interface Player {
address: Uint8Array; // Bytes<32>
score: bigint; // Uint<64>
isActive: boolean; // Boolean
}
Source: Representations in TypeScript
Recursive Structs Are Not Allowed
Structs cannot contain themselves directly or indirectly:
// ❌ ERROR: Recursive struct
struct Node {
value: Field,
next: Node // Not allowed!
}
// ❌ ERROR: Mutually recursive
struct Even {
predecessor: Odd
}
struct Odd {
predecessor: Even // Creates cycle - not allowed!
}
Source: User-defined types
Complete Example
pragma language_version >= 0.16;
// Define structs
struct PlayerStats {
wins: Uint<32>,
losses: Uint<32>,
draws: Uint<32>
}
struct Player {
address: Bytes<32>,
name: Bytes<32>,
stats: PlayerStats
}
// Pure circuit to create a new player
export pure circuit createPlayer(
address: Bytes<32>,
name: Bytes<32>
): Player {
return Player {
address: address,
name: name,
stats: PlayerStats { wins: 0, losses: 0, draws: 0 }
};
}
// Pure circuit to update stats after a win
export pure circuit recordWin(player: Player): Player {
const newStats = PlayerStats {
wins: (player.stats.wins + 1) as Uint<32>,
losses: player.stats.losses,
draws: player.stats.draws
};
return Player {
address: player.address,
name: player.name,
stats: newStats
};
}
Exercises
Complete exercises/05_user_types/01_structs/.