Instances and classes
Validate existing Dart instances and describe class fields.
Instances
Use instance<T>() to validate already constructed Dart objects (class instances) without converting them to Map.
You attach field validators via getters. Read the original instance from result.value; field validators do not rewrite the instance’s properties.
class User {
final String name;
final int age;
final String? email;
User(this.name, this.age, this.email);
}
final userSchema = instance<User>()
.field('name', (u) => u.name, string().min(3))
.field('age', (u) => u.age, number().positive())
.field('email', (u) => u.email, string().email(), optional: true);
userSchema.parse(User('Alice', 30, null)); // ✅
userSchema.parse(User('A', 30, null)); // ❌ ValidationError (name.min)INFO
A field flagged as optional will be skipped if the getter returns null.
Differences to object()
object()validatesMapdata (often decoded JSON).instance()validates real Dart objects via property getters.
Cross-field validation with refs
Define reusable references, then create a refinement that can access them.
class Order {
final int quantity;
final double unitPrice;
Order(this.quantity, this.unitPrice);
}
final orderSchema = instance<Order>()
.field('quantity', (o) => o.quantity, number().positive())
.field('unitPrice', (o) => o.unitPrice, number().positive())
.withRefs((r) => r
.ref<int>('qty', (o) => o.quantity)
.ref<double>('price', (o) => o.unitPrice)
)
.refineWithRefs(
(o, refs) => refs<int>('qty') * refs<double>('price') <= 1000,
'Total exceeds limit',
name: 'totalLimit',
);refineWithRefs supplies a RefAccessor so you can read previously registered references by name and perform cross-field logic.
Class Schemas
Use classSchema<I, T>() to build a typed pipeline that validates the input shape (I), maps the validated input into a class (T) via a pure mapper.
class User {
final String name;
final int age;
User(this.name, this.age);
}
final buildUser = classSchema<Map<String, dynamic>, User>()
.input(object({
'name': string().min(3),
'age': integer().positive(),
}))
.map((data) => User(data['name'] as String, data['age'] as int))
.validateWith(
instance<User>()
.field('name', (u) => u.name, string().max(50))
.field('age', (u) => u.age, number().gte(18)),
)
.build();
final user = buildUser.parse({
'name': 'Alice',
'age': 30,
}).value; // User instanceINFO
You can also validate the result of the mapping using validateWith and an instance() schema.
