π Syntax
Basic Format
"type --> Your custom error message"
The --> operator separates the type definition from your custom error message.
Key Points:
- Spaces around
-->are optional - Works with all type definitions, constraints, and modifiers
- TypeScript inference correctly strips the message
- Minimal performance impact
All these formats work:
// With spaces
"string --> Please provide your name"
// No space before
"string--> Please provide your name"
// No spaces at all
"string-->Please provide your name"
π Basic Usage
Simple Type Validation
import { Interface } from "fortify-schema";
const schema = Interface({
name: "string --> Please provide your name",
age: "number --> Age must be a valid number",
email: "email --> Please enter a valid email address",
});
const result = schema.safeParse({
name: 123, // Wrong type
});
console.log(result.errors[0].message);
// Output: "Validation failed: Please provide your name in field \"name\""
With Constraints
const ProductSchema = Interface({
price: "number(0.01,) --> Price must be greater than 0",
quantity: "int(1,1000) --> Quantity must be between 1 and 1000",
name: "string(3,100) --> Product name must be 3-100 characters",
});
With Union Types
const StatusSchema = Interface({
status: "pending|approved|rejected --> Status must be pending, approved, or rejected",
role: "admin|user|guest --> Invalid role selected",
});
π₯ Advanced Examples
Required Fields
Combine with ! modifier
email: "email! --> Email is required"
Optional Fields
Combine with ? modifier
phone: "string? --> Phone must be valid if provided"
Array Validation
Works with arrays too
tags: "string[] --> Must be an array of strings"
Complex Constraints
Multiple constraints
username: "string(3,20)! --> Username must be 3-20 chars"
Nested Objects
const ProfileSchema = Interface({
user: {
name: "string --> Name is required",
email: "email --> Please provide a valid email",
settings: {
theme: "light|dark --> Theme must be light or dark",
notifications: "boolean --> Must be enabled or disabled",
},
},
});
β¨ Best Practices
1. Be Clear and Actionable
Bad
name: "string --> Invalid"
Good
name: "string --> Please provide your full name"
2. Include Constraint Details
Bad
age: "number(18,65) --> Invalid age"
Good
age: "number(18,65) --> Age must be between 18 and 65"
3. Use Consistent Tone
const schema = Interface({
email: "email --> Please enter a valid email address",
phone: "string --> Please provide your phone number",
address: "string --> Please enter your full address",
});
4. Keep Messages Concise
π‘ Tip: Aim for messages under 100 characters. Users should understand the issue at a glance.
5. Consider Internationalization
// Use error codes for multi-language support
const schema = Interface({
email: "email --> ERR_INVALID_EMAIL",
});
// Map codes to localized messages
const messages = {
en: { ERR_INVALID_EMAIL: "Please enter a valid email" },
es: { ERR_INVALID_EMAIL: "Ingrese un correo vΓ‘lido" },
fr: { ERR_INVALID_EMAIL: "Entrez un e-mail valide" },
};
π― Type Inference
TypeScript correctly infers types even with custom error messages:
const schema = Interface({
status: "pending|approved|rejected --> Invalid status",
count: "number --> Count must be a number",
});
// TypeScript knows:
// status: "pending" | "approved" | "rejected"
// count: number
const data = schema.parse({
status: "pending", // β
TypeScript accepts this
// status: "invalid", // β TypeScript error: not in union
count: 42,
});
π‘ Pro Tip: The custom error message is completely transparent to TypeScript's type system. You get full type safety without any compromises!
π Combining with Other Features
With Conditional Validation
const schema = Interface({
accountType: "free|premium --> Account type must be free or premium",
maxProjects: "when accountType=free *? int(1,3) --> Free: 1-3 projects : int(1,100) --> Premium: 1-100 projects",
});
With Record Types
const ConfigSchema = Interface({
settings: "record --> Settings must be key-value pairs",
metadata: "record --> Metadata must be an object",
});
Mixed Required and Optional
const FormSchema = Interface({
// Required with custom message
email: "email! --> Email is required",
// Optional with custom message
phone: "string? --> Phone is optional but must be valid",
// Required with constraints
password: "string(8,)! --> Password must be at least 8 characters",
});
β FAQ
Can I use --> in the error message itself?
Yes! Only the first --> is used as the separator:
name: "string --> Use format: FirstName --> LastName"
// Type: string
// Message: "Use format: FirstName --> LastName"
What if I don't provide a custom message?
The default error message is used:
name: "string" // Default: "Expected String, but received ..."
Can I use emojis?
Absolutely! Emojis work perfectly:
email: "email --> π§ Please provide a valid email address",
age: "number(18,) --> π You must be 18 or older"
Does this affect performance?
Minimal impact. The message is extracted once during schema creation. Validation performance is nearly identical.
Which validators support custom messages?
| Feature | Supported |
|---|---|
| Basic types (string, number, boolean) | β Yes |
| Format types (email, url, uuid) | β Yes |
| Constraints (min, max, length) | β Yes |
| Union types | β Yes |
| Arrays | β Yes |
| Required fields (!) | β Yes |
| Optional fields (?) | β Yes |
| Nested objects | β Yes |