.refine() to add predicates or .reject() for dynamic error messages.
The refine() Method
The.refine() method adds a validation predicate to a decoder. If the predicate returns true, the value is accepted; otherwise, it’s rejected with the provided error message.
Built-in Refinements
Many built-in decoders are implemented using.refine():
Type Narrowing with refine()
You can use type predicates to narrow the TypeScript type:String Refinements
Number Refinements
Array Refinements
Object Refinements
The reject() Method
While.refine() uses a predicate that returns boolean, .reject() allows you to return dynamic error messages or null to accept.
reject() vs refine()
.reject() when:
- You need different error messages for different conditions
- The error message depends on the actual value
- You have multiple validation rules to check
.refine() when:
- You have a simple boolean check
- The error message is always the same
- You want type narrowing with type predicates
Chaining Refinements
You can chain multiple refinements together:Using Built-in Refinements
Many built-in decoders combine base decoders with refinements:Real-World Examples
Email Validation
Credit Card Validation
Business Logic Validation
When to Use Refinements
Use refinements when you need to:- Add validation rules beyond type checking
- Enforce business logic constraints
- Validate relationships between fields
- Apply domain-specific rules
- Create reusable validators
Performance Considerations
Refinements are checked after the base decoder succeeds, so:Next Steps
- Learn about transformations for modifying validated data
- Explore custom decoders for advanced use cases
- Check out the API reference for all decoder methods
