Schemas
Arrays
Validate List values with ZemaArray: length constraints, nested schemas, transformations, and refinements.
Validates List values. Every element is validated by the element schema. Validation is exhaustive: all element failures are collected before returning.
Signature:
ZemaArray<T> array<T>(ZemaSchema<dynamic, T> element)
Validation order: type check → length constraints → element validation.
If a length constraint fails, element validation is skipped entirely.
Basic usage
final schema = z.array(z.string());
schema.parse(['a', 'b', 'c']); // ['a', 'b', 'c']
schema.parse([1, 2, 3]); // throws ZemaException: invalid_type
schema.parse('not an array'); // throws ZemaException: invalid_type
Length constraints
.min(n)
Requires the list to have at least n elements. Produces too_small.
z.array(z.string()).min(2)
schema.parse(['a', 'b']); // ['a', 'b']
schema.parse(['a']); // throws ZemaException: too_small
.max(n)
Requires the list to have at most n elements. Produces too_big.
z.array(z.string()).max(5)
schema.parse(['a', 'b', 'c']); // ['a', 'b', 'c']
schema.parse(['a', 'b', 'c', 'd', 'e', 'f']); // throws ZemaException: too_big
.length(n)
Sets both minimum and maximum to n. Produces too_small or too_big.
z.array(z.string()).length(3)
schema.parse(['a', 'b', 'c']); // ['a', 'b', 'c']
schema.parse(['a', 'b']); // throws ZemaException
.nonEmpty()
Shorthand for .min(1). Produces too_small on an empty list.
z.array(z.string()).nonEmpty()
schema.parse(['a']); // ['a']
schema.parse([]); // throws ZemaException: too_small
Nested arrays
Array of arrays
final schema = z.array(z.array(z.integer()));
schema.parse([
[1, 2, 3],
[4, 5, 6],
]); // [[1, 2, 3], [4, 5, 6]]
schema.parse([
[1, 2, 3],
['a', 'b'], // invalid: not integers
]); // throws ZemaException
Array of objects
final schema = z.array(
z.object({
'id': z.integer(),
'name': z.string(),
}),
);
schema.parse([
{'id': 1, 'name': 'Alice'},
{'id': 2, 'name': 'Bob'},
]); // List<Map<String, dynamic>>
schema.parse([
{'id': 1, 'name': 'Alice'},
{'id': 'two', 'name': 'Bob'}, // invalid: id is not int
]); // throws ZemaException
Error paths
Element-level issues include the element index in their path:
final schema = z.array(z.object({'name': z.string()}));
final result = schema.safeParse([
{'name': 'Alice'},
{'name': 42}, // invalid
]);
// ZemaIssue(code: 'invalid_type', path: [1, 'name'], ...)
// → 'name' field of element at index 1
issue.pathString formats this as '[1].name'.
Transformations
// Map elements
final schema = z.array(z.string())
.transform((list) => list.map((s) => s.toUpperCase()).toList());
schema.parse(['hello', 'world']); // ['HELLO', 'WORLD']
// Filter elements
final positives = z.array(z.integer())
.transform((list) => list.where((n) => n > 0).toList());
positives.parse([1, -2, 3, -4, 5]); // [1, 3, 5]
Refinements
// All elements must be even
final schema = z.array(z.integer())
.refine(
(list) => list.every((n) => n % 2 == 0),
message: 'All numbers must be even',
);
schema.parse([2, 4, 6]); // [2, 4, 6]
schema.parse([2, 3, 4]); // throws ZemaException
// Unique elements
final unique = z.array(z.string())
.refine(
(list) => list.length == list.toSet().length,
message: 'Array must contain unique values',
);
unique.parse(['a', 'b', 'c']); // ['a', 'b', 'c']
unique.parse(['a', 'b', 'a']); // throws ZemaException
Common patterns
Tags
final tagsSchema = z.array(z.string())
.min(1)
.max(5)
.transform((tags) => tags.map((t) => t.toLowerCase()).toList());
tagsSchema.parse(['Flutter', 'Dart', 'Mobile']);
// ['flutter', 'dart', 'mobile']
Optional array with default
final userSchema = z.object({
'id': z.integer(),
'email': z.string().email(),
'roles': z.array(z.string()).withDefault([]),
});
userSchema.parse({
'id': 1,
'email': 'alice@example.com',
// 'roles' absent — defaults to []
});
Paginated response
final paginatedSchema = z.object({
'items': z.array(z.object({
'id': z.integer(),
'title': z.string(),
})),
'total': z.integer(),
'page': z.integer(),
'perPage': z.integer(),
});
final result = paginatedSchema.safeParse(responseBody);
Error codes
| Code | Trigger |
|---|---|
invalid_type | Input is not a List. |
too_small | Length below .min() or .nonEmpty(). |
too_big | Length above .max(). |
API reference
| Method | Description |
|---|---|
.min(n) | Minimum n elements. |
.max(n) | Maximum n elements. |
.length(n) | Exactly n elements. |
.nonEmpty() | Shorthand for .min(1). |
.optional() | null input passes through. |
.withDefault(v) | null input substitutes v. |