Repository navigation
10.0.0
Version 10.x represents a major step forward in Validator by enhancing type safety and developer experience while also further improving on performance. The overall API has been streamlined to better align with modern TypeScript practices. Key improvements include:
- Enhanced Type Inference & DX
-- A new schema getter lets you inspect the raw ruleset and automatically infer the validator’s output type.
-- The static create method now auto-infers types from your validation schema without extra type assertions. - Unified & Powerful Extension Mechanism:
-- The revamped extend method consolidates previous extension APIs, supporting key/value mappings with RegExp, enum arrays, and even nested schema objects.
-- This mechanism returns an adjusted Validator class, ensuring that custom extensions correctly augment type inference. - Branded Types & Better Rule Definitions:
-- Branded types (e.g., GeoLatitude, GeoLongitude, and others) are now built into the library for more precise validation. - Breaking Changes:
-- The DSL for conditional rule groups has been simplified for reduced cognitive overhead and improved clarity.
-- The deprecated required rule has been removed, and several legacy extension methods have been consolidated.
Added
- dx: Validator@schema getter which can be used to both understand the existing raw ruleset configured for a validator and infer the type of the validator from
- feat: Validator@create static which acts as a proxy for creating a new Validator while also automatically inferring a type off of the provided schema
const myValidator = Validator.create({
first_name: "string_ne|min:3",
last_name: "?string_ne",
role: 'user_role',
communication: ["?", "email", "phone"],
geo: {
lat: "geo_latitude",
lng: "geo_longitude",
},
});
type VType = typeof myValidator.schema;
/* At this point the type will be this */
{
first_name: string;
last_name: string | undefined;
/**
* Given Validator was extended
* Validator.extend({user_role: ["admin", "manager", "user", "guest"]})
*/
role: "admin" | "manager" | "user" | "guest";
communication: Email | Phone | undefined; /* Note the branded types here */
geo: {
lat: GeoLatitude;
lng: GeoLongitude;
};
}Improved
- feat: Validator@extend now works with kv-map setup
- feat: Validator@extend now also allows RegExp values on its kv-map (previously Validator@extendRegex)
- feat: Validator@extend now also allows string/number arrays on its kv-map (previously Validator@extendEnum)
- feat: Validator@extend now also allows schema extension objects (previously Validator@extendSchema)
Validator.extend({
/* Would define an enum-like rule */
is_fruit: ['apple', 'pear', 'orange'],
/* Function */
multipleOf2: val => Number.isFinite(val) && val % 2 === 0,
/* RegEx rule */
contains_hello: /((h|H)ello|(o|O)la)/,
/* Schema extension */
user: {
first_name: 'string_ne|min:3',
last_name: 'string_ne|min:3',
email: 'email',
phone: 'phone',
},
});- feat: Validator@extend will now return an adjusted class definition for Validator containing the rule extensions. Using this returned class as the base class to create Validators on ensures proper typing as well.
/* validator.ts: Example File somewhere in your project */
import {Validator} from '@valkyriestudios/validator';
const CustomValidator = Validator.extend({
is_fruit: ['apple', 'pear', 'banana', 'kiwi', 'orange', 'grape'],
user: {
first_name: 'string_ne',
last_name: 'string_ne',
phone: '?phone',
},
});
export default CustomValidator;
/* handler.ts: Example file somewhere in your project making use of the custom validator */
import Validator from './validator.ts';
const v = CustomValidator.create({
fruit: 'is_fruit',
users: '[]user',
type: 'string_ne',
});
type vType = typeof v.schema;
/* The above will result in: the following type: {
fruit: "apple" | "pear" | "banana" | "kiwi" | "orange" | "grape";
users: {
first_name: string;
last_name: string;
phone: Phone | undefined;
}[];
bla: string;
}*/- dx: A branded
GeoLatitudetype is now available for thegeo_latituderule as its typeguard - dx: A branded
GeoLongitudetype is now available for thegeo_longituderule as its typeguard - dx: All branded types are now exported from a root-level types file (for easy access)
import {type Continent, type GeoLatitude, type GeoLongitude} from '@valkyriestudios/validator/types';
...- deps: Upgrade @valkyriestudios/utils to 12.31.1
- deps: Upgrade @types/node to 22.13.4
- deps: Upgrade eslint to 9.20.1
- deps: Upgrade typescript to 5.7.3
- deps: Upgrade typescript-eslint to 8.24.0
Breaking
- rules: The syntax for conditional rule groups has had an overhaul to allow for less cognitive overhead, easier understanding of the rules at play as well as further improvements regarding type safety and automatic inference down the line.
/* old way of defining, the below would validate that first_name needs to be a string with at least 3 chars OR null */
const v = new Validator({
first_name: '(string_ne|min:3)(null)',
});
/* new way of defining */
const v = new Validator({
first_name: ['string_ne|min:3', 'null'],
});
/* Optionality: old way of defining, the below would validate that uid can be passed but needs to be a guid or null if passed */
const v = new Validator({
uid: '?(guid)(false)',
});
/* New way of defining */
const v = new Validator({
uid: ['?', 'guid', 'false'], /* Note the special '?' rule here */
});- rules:
requiredas a rule has been removed as this rule did nothing other than tell you a value is not empty and as such does not help in truly validating the contents of the value, on top of this it caused conflicting behavior when determining the type of something. For those whishing to 'recreate' the behaviors of this rule you can always apply the following conditional:
['string_ne', 'number', 'array_ne', 'object_ne'].
Removed
- Validator@extendMulti (see improved)
- Validator@extendEnum (see improved)
- Validator@extendRegex (see improved)
- Validator@extendSchema (see improved)