Schemas
Map
Validate dynamic Map<K, V> values with ZemaMap: key and value schemas, size constraints, and typed output.
Validates Map values where every key and every value are validated by their respective schemas. Produces a typed Map<K, V>. Validation is exhaustive, all entry failures are collected before returning.
Signature:
ZemaMap<K, V> map<K, V>(ZemaSchema<dynamic, K> keySchema, ZemaSchema<dynamic, V> valueSchema)
Validation order: type check → size constraints → entry validation (exhaustive).
If a size constraint fails, entry validation is skipped entirely.
ZemaMap vs ZemaObject
z.map() | z.object() | |
|---|---|---|
| Keys | Dynamic — any number, validated uniformly | Fixed — defined in the shape |
| Use case | Dictionaries, lookup tables | Structured records |
| Output type | Map<K, V> | Map<String, dynamic> or T |
Basic usage
// String keys → integer values
final scoreSchema = z.map(
z.string(),
z.integer().gte(0),
);
scoreSchema.parse({'alice': 95, 'bob': 87});
// Map<String, int>: {'alice': 95, 'bob': 87}
scoreSchema.parse({'alice': 95, 'bob': -1});
// throws ZemaException: too_small at path 'bob'
Key constraints
Any schema can be used as the key schema:
// Non-empty string keys only
final headers = z.map(
z.string().min(1),
z.string(),
);
headers.parse({'': 'value'});
// throws ZemaException: too_short at path ''
Size constraints
.min(n)
Requires the map to have at least n entries. Produces too_small.
z.map(z.string(), z.integer()).min(1) // non-empty
schema.parse({}); // throws ZemaException: too_small
schema.parse({'a': 1}); // Map<String, int>: {'a': 1}
.max(n)
Requires the map to have at most n entries. Produces too_big.
z.map(z.string(), z.string()).max(50)
Error paths
Entry-level issues include the entry's key in their path:
final schema = z.map(z.string(), z.integer());
final result = schema.safeParse({'a': 1, 'b': 'bad'});
// ZemaIssue(code: 'invalid_type', path: ['b'], ...)
// → value at key 'b' failed
issue.pathString formats this as 'b'.
Common patterns
User scores
final scoresSchema = z.map(
z.string().uuid(), // user ID as key
z.integer().gte(0).lte(100), // score as value
);
scoresSchema.parse({
'550e8400-e29b-41d4-a716-446655440000': 87,
'a3bb189e-8bf9-3888-9912-ace4e6543002': 92,
});
HTTP headers
final headersSchema = z.map(
z.string().min(1),
z.string(),
);
headersSchema.parse({
'Content-Type': 'application/json',
'Authorization': 'Bearer token',
});
Feature flags
final flagsSchema = z.map(
z.string(),
z.boolean(),
).min(1);
flagsSchema.parse({
'dark_mode': true,
'beta_features': false,
});
Translations
final translationsSchema = z.map(
z.string().regex(RegExp(r'^[a-z]{2}$')), // ISO 639-1 locale
z.string().min(1),
);
translationsSchema.parse({
'en': 'Hello',
'fr': 'Bonjour',
'de': 'Hallo',
});
Error codes
| Code | Trigger |
|---|---|
invalid_type | Input is not a Map. |
too_small | Entry count below .min(). |
too_big | Entry count above .max(). |
Plus any error codes produced by keySchema or valueSchema.
API reference
| Method | Description | Error code |
|---|---|---|
.min(n) | Minimum n entries. | too_small |
.max(n) | Maximum n entries. | too_big |
.optional() | Allow null input. | — |
.withDefault(v) | Substitute null with v. | — |