TypeScript validation utilities for fluent object, array, field, string, number, date, file, and image checks.
The package builds to both ESM and CommonJS, ships declaration files, and supports both synchronous and asynchronous validation flows.
- docs/index.md
- docs/checks.md
- docs/how-to.md
- docs/coded-results.md
- docs/development.md
- docs/publishing.md
This package is a good fit when validation is part of application logic instead of a one-off form helper.
Typical uses:
- data ingestion pipelines that need to validate imported records before persistence
- data quality audits that need both nested findings and flattened issue lists
- API boundary validation for request payloads, events, or jobs
- admin or back-office tooling that needs warnings and hints, not just hard failures
- file and image intake flows that need MIME, size, or dimension checks
npm install @samatawy/checksThe core object, array, string, number, and date validators work with just the main package.
If you use FileCheck, ImageCheck, field.file(), or field.image(), also install the binary inspection peer dependencies:
npm install @samatawy/checks file-type probe-image-sizeWhy these are optional:
file-typeis used to detect MIME types from file buffersprobe-image-sizeis used for image metadata in Node runtimes- browser image dimension checks can also use browser-native APIs
import { ObjectCheck } from '@samatawy/checks';
const check = await ObjectCheck.for({
name: 'Sam',
age: 34,
address: {
city: 'Cairo'
}
})
.notEmpty()
.check(person => [
person.required('name').string().minLength(2),
person.optional('age').number().atLeast(18),
person.required('address').object().check(address => [
address.required('city').string()
])
]);
const result = check.result({ language: 'en' });
if (!result.valid) {
console.error(result.results);
}check, isTrue, checkEach, isTrueEach, file, and image may all become async depending on the validators you use, so await at the outer rule boundary is the safe default.
The package now uses result(options?) as the main output API.
For object and array checks:
result({ language })returns the merged nested result treeresult({ flattened: true, language })returns flattenedhints,warnings, anderrorsresult({ nested: true, language })returns an input-shaped projection underinputresult({ raw: true, nested: true, flattened: true, language })returns all projections at once
For value-level checks such as FieldCheck, StringCheck, or NumberCheck, result({ language }) returns the finalized single result.
Example:
const output = check.result({
raw: true,
nested: true,
flattened: true,
language: 'en'
});
console.log(output.raw);
console.log(output.input);
console.log(output.errors);Use result() with no options when you want the current internal result state while building advanced flows. For application-facing output, prefer explicit result options.
Everything is exported from the package root in src/index.ts.
ObjectCheckFieldCheckArrayCheckArrayItemCheckStringCheckEmailCheckUrlCheckNumberCheckDateCheckFileCheckImageCheckValueCheck
CheckCheckOptionsStringCheckOptionsTolerantCheckOptionsIResultSingleResultResultSetResultCodeResultCodeDefinitionIResultCatalog
ResultCatalogResultCatalog.global
The fluent API accumulates validation output while you compose rules.
required(name)asserts that a field existsoptional(name)starts a field check without requiring presenceconditional(name, condition)requires a field only when another condition is metnoExtraFields()rejects undeclared object keys in final object resultscheck(...)applies nested object or array rulescheckEach(...)applies nested rules to each array itemnoDuplicates()rejects duplicate array values or duplicate keys when you provide a selector keyisTrue(...)andisTrueEach(...)add custom predicatesfile()andimage()create asynchronously initialized binary validatorsemail()andurl()branch into specialized string validators
String-related inheritance:
StringCheck,EmailCheck, andUrlCheckshare common string comparison methods through the internalStringBaseCheckStringBaseCheckitself is not part of the public API
Stable result codes and translated output are supported, but they are optional. If you just need direct inline messages, you can ignore that layer entirely.
The dedicated guide is here:
import { ObjectCheck } from '@samatawy/checks';
const check = await ObjectCheck.for(input).check(person => [
person.optional('avatar').file().then(file =>
file.notEmpty()
.mimeType('image/*')
.minSize(5 * 1024)
.maxSize(5 * 1024 * 1024)
),
person.optional('avatar').image().then(image =>
image.isImage()
.minWidth(200)
.minHeight(200)
.maxWidth(2000)
.maxHeight(2000)
)
]);
const result = check.result({ flattened: true, language: 'en' });npm install
npm run lint
npm test
npm run buildUseful scripts:
npm run buildbuilds ESM, CJS, and declaration files intodist/npm run devwatches the package entrypointnpm run lintruns TypeScript type checkingnpm testruns the Vitest suite oncenpm run test:watchruns Vitest in watch mode
When validating integration in this workspace, use the package build output from dist/ and then rebuild the local consumer package if it depends on file:../checks.
MIT