Simple and extensible schema based validator with support for typescript typing.
The example below represents a basic subset of the inline validations that can be applied.
import { Email, ID, RegEx, Type, Options, Optional, Nullable, Alias, Any, All, validate } from 'validate-typescript';
function ZaPhoneNumber() {
return Alias(RegEx(/^((\+27|0)\d{9})$/), ZaPhoneNumber.name);
}
class CustomMessage {
constructor(public message: string) {}
}
const schema = {
id: ID(),
children: [ID()],
username: Type(String),
email: Email(),
gmail: RegEx(/.+@gmail.com/),
phone: ZaPhoneNumber(),
gender: Options(['m', 'f', 'o']),
married: Type(Boolean),
names: {
first: Type(String),
middle: Optional(Type(String)),
last: Type(String)
}
message: Type(CustomMessage)
}
const input = {
id: 17,
children: [1,2,'3'],
username: 'solomon',
email: 'solomon@validate-typescript.com',
gmail: 'solomon@gmail.com',
phone: '+27824392186'
gender: 'm',
married: true,
names: {
first: 'Solomon',
last: 'Dube',
}
message: new CustomMessage('Sawubona Mhlaba')
}
try {
const input = validate(schema, input);
console.log(input); // no validation error
} catch (error) {
console.log(error); // validation error
}
npm install validate-typescript
The default import provides validate
, all the validators
and all the extensions
:
import { ... } from 'validate-typescript';
The following examples of validate-typescript
schemas illustrate the different validation methods.
Note: the comment // type: TypeName
following the validator explicitly specifies the resultant typescript type inferred by the typescipt transpiler. This relates back to the strongly typed criteria.
Expects an exact type match.
let schema = {
myNumber: Type(Number), // type: Number
myString: Type(String), // type: String
myCustom: Type(CustomClass), // type: CustomClass
// etc...
}
Expects an exact primitive type match.
let schema = {
myNumber: Primitive(Number), // type: number
myString: Primitive(String), // type: string
// etc...
}
Expects an exact type and value match.
let schema = {
number49: 49, // type: number
myCountry: 'South Africa', // type: string
dontDefine: undefined, // type: undefined
allwaysNull: null, // type: null
// etc...
}
Expects custom convertions and assertions to be valid.
let schema = {
myEmail: Email(), // type: string
sqlId: ID(), // type: number
comeText: RegEx(/abc/), // type: string
// etc...
}
Expects a nested object that matches the nested schema.
let schema = {
subObject: {
a: ID(),
b: Type(Date)
c: {
d: RegEx(/.+@gmail.com/)
}
} // type: { a: number, b: Date, c: { d: string } }
}
Expects an array that matches the contents of the array schema.
Note: Multiple validators in the array are treated as boolean-or (any).
let schema = {
// array validation
emailArray: [Email()] // type: string[]
idArray: [ID()] // type: number[]
// array with multiple options validation
arrayOfEmailOrId: [Email(), ID()] // type: (string | number)[]
}
Expects any or all of the validation options to match.
let schema = {
// options validation
options: Options([Type(Number), Type(String)]) // type: number | string
// optional validation (i.e. not required)
optional: Optional(ID()) // type: number | undefined
alsoOptional: Options([ID(), undefined]) // type: number | undefined
// nullable validation
maybeNull: Nullable(Type(String)), // type: String | null
alsoMaybeNull: Options([Type(String, null)]), // type: String | null
// array options
arrayOptions: Options([[Email()], [ID()]]) // type: string[] | number[]
}
Any represents boolean-or of the validation options while all represents boolean-and.
let schema = {
// validate any options
anyOptions: Options([Type(Number), Type(String)], ValidationOptions.any) // type: number | string
alsoAny: Any([Type(Number), Type(String)]) // type: number | string
// validate all options
allOptions: Options([RegEx(/.+@gmail.com/), Email()], ValidationOptions.all) // type: number | string
alsoAll: All([RegEx(/.+@gmail.com/), Email()]) // type: number | string
}
Note: the return of validate
, in this case input
, will inherit the typescript typing of the schema, thus strongly-typed.
try {
const input = validate(schema, input);
console.log(input); // no validation error
} catch (error) {
console.log(error); // validation error
}
Assertions allow enforcing of basic validation conditions and form the atomic building blocks of custom validators. Upon failure, assertions throw an AssertionError
.
Note: All assertions take a flag allowing conditional inversion.
Assertions are intended to be extended.
Assertion | Description |
---|---|
isSameType | Assert type equality of two inputs. |
isSameTypeName | Asserts type name equality of two inputs. |
isSymbol | Asserts symbol type input. |
isBoolean | Asserts boolean type input. |
isString | Asserts string type input. |
isNumber | Asserts number type input. |
isArray | Asserts array type input. |
isNull | Asserts null type input. |
isObject | Asserts object type input. |
isUndefined | Asserts undefined type input. |
Assertion | Description |
---|---|
isInt | Asserts integer input. |
isFloat | Asserts float input. |
Assertion | Description |
---|---|
isEqualTo | Asserts equality (==) of two inputs. |
isGreaterThan | Asserts greater than relation (>) of two inputs. |
isLessThan | Asserts less than relation (<) of two inputs. |
isGreaterThanOrEqualTo | Asserts greater than or equal to relation (>=) of two inputs. |
isLessThanOrEqualTo | Asserts less than or equal to relation (<=) of two inputs. |
Assertion | Description |
---|---|
isEqual | Asserts typed equality (===) of two inputs. |
isRegEx | Asserts RegExp matching input. |
All converters attempt to convert the input to a specific type and throw a ConversionError
if the conversion fails.
Converters are intended to be extended.
Conversion | Output Type | Input Types | Description |
---|---|---|---|
toInt | number |
number , string |
Converts only integers (needs updating) |
toNumber | number |
number , string |
Converts any number |
toBoolean | boolean |
boolean , string |
Converts 'true' and 'false' (needs updating) |
Custom validation errors are implemented. It is ulikely that you will need to extend these but there may be future extensions.
- ValidationError: Abstract base class for all validation errors.
- ConversionError: Type of all the conversion errors.
- AssertionError: Type of all the assertion errors.
- ValidationError: Type of all the validation errors.
- NotMatchAnyError: Type of error thrown when
Any
does not match any of the provided validation options.
For example, supporting JSON formatted validation errors for easier parsing and logging.
Validators can be customized using converters, assertions as well as other custom validators (extensions). Upon failure, validators throw a ValidationError
.
Aliasing is a method of aliasing a custom validator, possibly with inputs.
import { RegEx, Alias } from 'validate-typescript';
export function ZaPhoneNumber() {
return Alias(RegEx(/^((\+27|0)\d{9})$/), ZaPhoneNumber.name);
}
This example illustrates the use of both a converter and an assertion.
import { Validator } from 'validate-typescript';
import * as convert from 'validate-typescript/conversions';
export function ID() {
return Validator((input: any): number => {
const value = convert.toInt(input);
assert.isGreaterThan(0, value);
return value;
}, ID.name);
}
This example illustrates only the use of assertions.
import { Validator } from 'validate-typescript';
import * as assert from 'validate-typescript/assertions';
export function RegEx(regEx: RegExp) {
return Validator((input: any): string => {
assert.isString(input);
assert.isRegEx(regEx, input);
return input;
}, RegEx.name);
}