dynz
v0.0.14
Published
A powerful TypeScript schema validation with advanced conditional logic, cross-field validation, and static type inference.
Maintainers
Readme
dynz
A powerful TypeScript schema validation library with advanced conditional logic, cross-field validation, and privacy controls.
Features
🔒 Type-Safe Validation - Full TypeScript support with strong typing and inference
🔄 Conditional Logic - Dynamic validation rules based on field values
🎯 Cross-Field Validation - Reference other fields in validation rules
🔐 Privacy Controls - Built-in field masking for sensitive data
⚡ Performance Optimized - Efficient validation with minimal overhead
🧩 Framework Agnostic - Works with any JS frameworks
Installation
npm install dynz
# or
pnpm add dynz
# or
yarn add dynzQuick Start
import { object, string, number, validate, eq, min, email } from "dynz";
// Define a schema
const userSchema = object({
fields: {
name: string({ rules: [min(2)] }),
email: string({ rules: [email()] }),
age: number({ rules: [min(18)] }),
},
});
// Validate data
const result = validate(userSchema, undefined, {
name: "John Doe",
email: "[email protected]",
age: 25,
});
if (result.success) {
console.log("Valid data:", result.values);
} else {
console.log("Validation errors:", result.errors);
}Core Concepts
Schema Types
dynz supports comprehensive schema types for all common data structures:
import { string, number, boolean, object, array, max, min, regex } from "dynz";
// String schema with validation rules
const nameSchema = string({
rules: [min(2), max(50), regex("^[a-zA-Z\\s]+$")],
});
// Number schema with constraints
const ageSchema = number({
rules: [min(0), max(120)],
});
// Object schema with nested fields
const userSchema = object({
fields: {
profile: object({
fields: {
name: string({ rules: [min(1)] }),
bio: string({ required: false }),
},
}),
},
});
// Array schema
const tagsSchema = array({
schema: string({ rules: [min(1)] }),
rules: [min(1), max(5)],
});Validation Rules
Extensive validation rules for precise data validation:
import {
object,
string,
min,
max,
email,
number,
regex,
isNumeric,
options,
} from "dynz";
const productSchema = object({
fields: {
name: string({ rules: [min(1), max(100)] }),
email: string({ rules: [email()] }),
price: number({ rules: [min(0)] }),
category: options({ options: ["electronics", "books", "clothing"] }),
sku: string({ rules: [regex("^[A-Z]{3}-\\d{4}$")] }),
quantity: string({ rules: [isNumeric()] }),
},
});Conditional Logic
dynz excels at dynamic validation based on other field values:
import {
eq,
and,
or,
conditional,
email,
min,
object,
oneOf,
regex,
string,
options,
} from "dynz";
const userSchema = object({
fields: {
accountType: options({
options: ["personal", "business"],
}),
// Required only for business accounts
companyName: string({
rules: [min(2)],
required: eq("accountType", "business"),
}),
// Different validation rules based on account type
email: string({
rules: [
email(),
conditional({
when: eq("accountType", "business"),
then: regex(
"@company\\.com$",
"Business accounts must use company email",
),
}),
],
}),
// Complex conditional logic
specialField: string({
required: and(
eq("accountType", "business"),
or(eq("industry", "finance"), eq("industry", "healthcare")),
),
}),
},
});Cross-Field References
Reference other fields in validation rules:
import {
after,
dateString,
equals,
max,
min,
object,
ref,
string,
validate,
} from "dynz";
const signupSchema = object({
fields: {
password: string({ rules: [min(8)] }),
confirmPassword: string({
rules: [equals(ref("password"), "Passwords must match")],
}),
birthYear: dateString({
format: "yyyy",
rules: [min("1900"), max("2024")],
}),
graduatedAt: dateString({
format: "yyyy",
rules: [
after(ref("birthYear"), "Graduation date must be after birth year"),
],
}),
},
});Mutability Controls
Control when fields can be modified based on conditions:
function buildSchema(user: { role: "admin" | "user" }) {
return object({
fields: {
status: options({
options: ["draft", "published"],
}),
title: string({
rules: [min(1)],
mutable: user.role === "admin",
}),
content: string({
mutable: eq("status", "draft"),
}),
createdAt: string({
mutable: false, // Never mutable
}),
},
});
}Mutability on array schemas
You can also control mutability on inner schemas of an array. This allows you to add new elements or remove elements, but not to mutate elements on the same index.
const schema = array({
// The array is mutable
schema: string({
mutable: false, // The inner schema is immutable
}),
});
validate(schema, [], ["foo"]); // Validates successfully, because it's a new entry
validate(schema, ["foo"], []); // Validates successfully, because an entry is removed
validate(schema, ["foo"], ["bar"]); // Returns an error since 'foo' is mutated into 'bar'Field Inclusion
Dynamically include or exclude fields:
const registrationSchema = object({
fields: {
dietryRestrictions: boolean(),
dietryDetail: string({
included: eq("dietryRestrictions", true),
}),
},
});Advanced Usage
Custom Rules
Create reusable custom validation logic:
const passwordStrengthRule = custom('passwordStrength', {
minScore: 4,
requireSpecialChars: true
})
const passwordStrengthRuleValidator: CustomRuleFunction = (value, params) => {
...
}
const strongPasswordSchema = string({
rules: [min(8), passwordStrengthRule]
})
validate(strongPasswordSchema, undefined, 'myStrongPassword', {
customRules: {
passwordStrength: passwordStrengthRuleValidator
}
})
Complex Conditional Schemas
const orderSchema = object({
fields: {
orderType: options({ options: ["standard", "express", "international"] }),
shippingMethod: options({
options: ["overnight", "same-day", "air", "sea"],
rules: [
conditional({
when: eq("orderType", "express"),
then: oneOf(["overnight", "same-day"]),
}),
conditional({
when: eq("orderType", "international"),
then: oneOf(["air", "sea"]),
}),
],
required: or(
eq("orderType", "express"),
eq("orderType", "international"),
),
}),
customsInfo: object({
fields: {
value: number({ rules: [min(0)] }),
description: string({ rules: [min(1)] }),
},
included: eq("orderType", "international"),
}),
},
});Mutable Conditions in Practice
// Order management with status-based mutability
const orderSchema = object({
fields: {
orderStatus: options({
options: ["draft", "pending", "send"],
// always immutable
mutable: false,
}),
items: array({
schema: string(),
mutable: or(eq("orderStatus", "draft"), eq("orderStatus", "pending")),
}),
shippingAddress: string({
mutable: and(
or(eq("orderStatus", "draft"), eq("orderStatus", "pending")),
),
}),
},
});API Reference
Schema Builders
string(options?)- String validation schemanumber(options?)- Number validation schemaboolean(options?)- Boolean validation schemaobject({ fields })- Object schema with nested fieldsarray({ schema })- Array schema with item validationdateString(options?)- Date string validation with format supportoptions({ options })- Enum-like validation for predefined valuesfile(options?)- File validation schema
Validation Rules
min(value, message?)- Minimum value/lengthmax(value, message?)- Maximum value/lengthbefore(value, message?)- Before value/lengthafter(value, message?)- After value/lengthemail(message?)- Email format validationregex(pattern, message?)- Regular expression validationequals(value, message?)- Exact value matchingoneOf(values, message?)- Must be one of specified valuesisNumeric(message?)- Numeric string validationcustom(name, params?, message?)- Custom validation rule
Conditions
eq(field, value)- Field equals valueneq(field, value)- Field not equals valuegt(field, value)- Field greater than valuegte(field, value)- Field greater than or equallt(field, value)- Field less than valuelte(field, value)- Field less than or equalmatches(field, pattern)- Field matches regex patternand([...conditions])- All conditions must be trueor([...conditions])- At least one condition must be true
Validation
validate(schema, currentValues?, newValues, options?)- Main validation functionvalidateMutableoption - Check field mutability constraints (defaults to true)customRulesoption - Provide custom rule implementations
Type Safety
dynz provides excellent TypeScript integration:
import {
array,
min,
number,
object,
string,
validate,
SchemaValues,
} from "dynz";
const schema = object({
fields: {
name: string({ rules: [min(1)] }),
age: number({ required: false }),
tags: array({ schema: string() }),
},
});
// Inferred type: { name: string; age?: number; tags: string[] }
type UserData = SchemaValues<typeof schema>;
// Type-safe validation results
const result = validate(schema, undefined, {
name: "John",
tags: ["dynz"],
});
if (result.success) {
// result.values is properly typed as UserData
console.log(result.values.name); // ✅ Type-safe access
}Examples
Check out the /examples directory for complete working examples:
- Next.js Example - React forms with dynz schemas
Comparison with Other Libraries
| Feature | dynz | Zod | Yup | Joi | | ---------------------- | -------------- | --------- | ---------- | ---------- | | TypeScript Support | ✅ Native | ✅ Native | ⚠️ Partial | ❌ Runtime | | Conditional Validation | ✅ Built-in | ⚠️ Manual | ⚠️ Limited | ⚠️ Limited | | Cross-field References | ✅ Native | ⚠️ Manual | ✅ Native | ✅ Native | | Privacy/Masking | ✅ Built-in | ❌ | ❌ | ❌ | | Mutability Controls | ✅ Native | ❌ | ❌ | ❌ | | Field Inclusion | ✅ Conditional | ❌ | ❌ | ❌ | | Bundle Size | 🟡 Medium | 🟢 Small | 🟡 Medium | 🔴 Large |
Advanced Features
Complex Business Logic
const loanApplicationSchema = object({
fields: {
applicantType: string({ rules: [oneOf(["individual", "business"])] }),
income: number({
rules: [min(0)],
required: eq("applicantType", "individual"),
}),
businessRevenue: number({
rules: [min(0)],
required: eq("applicantType", "business"),
}),
loanAmount: number({
rules: [
min(1000),
conditional({
when: eq("applicantType", "individual"),
then: max(ref("income")), // Can't exceed annual income
}),
conditional({
when: eq("applicantType", "business"),
then: max(ref("businessRevenue")), // Can't exceed annual revenue
}),
],
}),
},
});Workflow Management
const documentWorkflowSchema = object({
fields: {
content: string({
mutable: and([
eq("status", "draft"),
or([eq("isOwner", true), eq("hasEditPermission", true)]),
]),
}),
status: string({
rules: [oneOf(["draft", "review", "approved", "published"])],
mutable: or([
and([eq("currentStatus", "draft"), eq("isOwner", true)]),
and([eq("currentStatus", "review"), eq("userRole", "reviewer")]),
eq("userRole", "admin"),
]),
}),
},
});Contributing
We welcome contributions! Please see our Contributing Guide for details.
License
MIT © dynz
Related Packages
- More framework integrations coming soon...
Built with ❤️ for type-safe validation
