Runtime type validation with TypeScript inference.
TypeScript provides excellent compile-time type safety, but those types disappear at runtime. When data crosses boundaries (API responses, user input, file parsing), you need runtime validation that stays in sync with your TypeScript types.
Most validation libraries introduce heavy dependencies or require maintaining separate schemas alongside your types. Property Validator provides lightweight runtime validation that infers directly from TypeScript types, with zero external dependencies.
- Zero runtime dependencies (Node.js standard library only)
- TypeScript-first design with automatic type inference
- Framework-agnostic (works with React, Vue, Svelte, vanilla JS)
- Clear, actionable error messages
- Composable validators for complex types
- Works as CLI tool or library
Clone the repository:
git clone https://github.com/tuulbelt/property-validator.git
cd property-validator
npm install # Install dev dependencies onlyNo runtime dependencies — this tool uses only Node.js standard library.
CLI names — both short and long forms work:
- Short (recommended):
propval - Long:
property-validator
Recommended setup — install globally for easy access:
npm link # Enable the 'propval' command globally
propval --helpFor local development without global install:
npx tsx src/index.ts --helpimport { validate, v } from '@tuulbelt/property-validator';
// Define validators inline
const userValidator = v.object({
name: v.string(),
age: v.number(),
email: v.string().email()
});
// Validate data
const result = validate(userValidator, {
name: "Alice",
age: 30,
email: "alice@example.com"
});
if (result.ok) {
console.log(result.value); // Typed as { name: string, age: number, email: string }
} else {
console.error(result.error); // Clear error message
}Using short name (recommended after npm link):
# Validate JSON from stdin
echo '{"name":"Alice","age":30}' | propval --schema user.schema.json
# Validate a file
propval --schema user.schema.json data.json
# Show help
propval --helpUsing long name:
property-validator --schema user.schema.json data.jsonValidate data against a validator.
Parameters:
validator— Validator instance (created withv.*functions)data— Unknown data to validate
Returns:
Result<T>object with:ok: trueandvalue: Tif validation succeededok: falseanderror: stringif validation failed
v.string()— String validatorv.number()— Number validatorv.boolean()— Boolean validatorv.array(itemValidator)— Array validatorv.object(shape)— Object validator with shapev.optional(validator)— Optional fieldv.nullable(validator)— Nullable field
import { v, Validator } from '@tuulbelt/property-validator';
// Create custom validator
const emailValidator: Validator<string> = {
validate(data: unknown): data is string {
return typeof data === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data);
},
error(data: unknown): string {
return `Expected email, got: ${typeof data}`;
}
};
// Use in object schema
const userValidator = v.object({
email: emailValidator
});See the examples/ directory for runnable examples:
npx tsx examples/basic.tsnpm test # Run all tests
npm test -- --watch # Watch modeTuulbelt tools validate each other via devDependencies. This tool uses:
- test-flakiness-detector to validate test determinism
- output-diffing-utility to verify validation output is deterministic
How It Works:
npm run dogfood # Runs both flaky detection + output diff validation
npm run dogfood:flaky # Runs tests 10 times to catch flaky tests
npm run dogfood:diff # Validates output determinism via diffThis runs automatically in CI on every push/PR.
Why This Matters:
- Validation must be deterministic (same input → same output, every time)
- test-flakiness-detector ensures tests don't randomly fail
- output-diffing-utility proves validation produces consistent results
- Critical for caching, reproducible builds, and reliable testing
Configuration (package.json):
{
"scripts": {
"dogfood": "npm run dogfood:flaky && npm run dogfood:diff",
"dogfood:flaky": "flaky --test 'npm test' --runs 10",
"dogfood:diff": "bash scripts/dogfood-diff.sh"
},
"devDependencies": {
"@tuulbelt/test-flakiness-detector": "git+https://github.com/tuulbelt/test-flakiness-detector.git",
"@tuulbelt/output-diffing-utility": "git+https://github.com/tuulbelt/output-diffing-utility.git"
}
}See DOGFOODING_STRATEGY.md for the decision tree on when to add additional Tuulbelt tools as devDependencies.
Exit codes:
0— Success1— Error (invalid input, validation failure)
Errors are returned in the error field of the result object, not thrown.
Planned improvements for future versions:
- Constraints:
.min(),.max(),.pattern()for strings/numbers - Better error paths: Show full property path in nested objects (e.g.,
user.address.city) - oneOf(): Union/enum validation for multiple type options
- TypeScript inference utility:
TypeOf<typeof schema>for extracting inferred types
- Schema generation from existing TypeScript types
- Custom error message templates
- Async validators for database/API checks
- Optimizations for large datasets
- Streaming validation for large files
- Cached validator compilation
- Plugin API for custom type handlers
- Schema versioning and migration utilities
- Benchmarking suite against other validators
- JSON Schema standard compatibility layer
- Binary serialization format for schemas
▶ View interactive recording on asciinema.org
Demos are automatically generated and embedded via GitHub Actions when demo scripts are updated.
MIT — see LICENSE
See CONTRIBUTING.md for contribution guidelines.
Part of the Tuulbelt collection:
- Test Flakiness Detector — Detect unreliable tests
- CLI Progress Reporting — Concurrent-safe progress updates
- More tools coming soon...
