Skip to main content

Guards

Guards are the most basic way to match against an atomic value (string, number, or more specifically emails or telephone numbers). These include built-in guards (e.g. vality.string, vality.boolean), but can be easily extended to check for more specific types such as domains or ip addresses.

ts
import { vality } from "vality";
 
validate(vality.string, "Hello There!"); // { valid: true }
ts
import { vality } from "vality";
 
validate(vality.string, "Hello There!"); // { valid: true }

Casting

By default, guards can cast certain values to the desired format.

ts
validate(vality.boolean, "1"); // { valid: true, data: true }
ts
validate(vality.boolean, "1"); // { valid: true, data: true }

This behaviour can be disabled by enabling strict mode.

Options

Guards also accept arguments to further constrain the type of the value they match against. These are passed by calling the guard with the options as only argument. You can find a list of supported options in the list of guards.

ts
vality.string({ minLength: 3 }); // String with at least 3 characters
vality.string({ minLength: 3, maxLength: 8 }); // String with at least 3 and at most 8 characters
vality.number({ m }); // We even get autocomplete here!
                 
ts
vality.string({ minLength: 3 }); // String with at least 3 characters
vality.string({ minLength: 3, maxLength: 8 }); // String with at least 3 and at most 8 characters
vality.number({ m }); // We even get autocomplete here!
                 

Extra Options

In addition to above described, there are a few more extra options that can be used to fully customise how a guard behaves.

transform

This option can be used to modify the value that a guard returns after all its checks have passed.

ts
validate(
vality.string({
transform: s => s.toUpperCase(),
}),
"Hello!"
); // { valid: true, data: "HELLO!" }
ts
validate(
vality.string({
transform: s => s.toUpperCase(),
}),
"Hello!"
); // { valid: true, data: "HELLO!" }

default

This option can be used to provide a default value to a guard that is used when undefined is validated. (vality.optional is useless in combination with this object).

ts
validate(
{
myNum: vality.number({
default: -1,
}),
},
{}
); // { valid: true, data: { myNum: -1 } }
ts
validate(
{
myNum: vality.number({
default: -1,
}),
},
{}
); // { valid: true, data: { myNum: -1 } }

validate

This option can be used to completely customise the way a guard validates an input. Note that this option does not replace, but adds another condition to the original guard definition.

ts
validate(
vality.number({
validate: n => n % 3 === 0
}),
5
); // { valid: false }
ts
validate(
vality.number({
validate: n => n % 3 === 0
}),
5
); // { valid: false }

preprocess

This option can be used to do anything with the value before it is validated in any way.

ts
validate(
vality.array(vality.number)({
preprocess: val => {
try {
return JSON.parse(val as string);
} catch (e) {
return val;
}
}
}),
`["1",2,"3",4,5]`
); // { valid: true, data: [1,2,3,4,5] }
ts
validate(
vality.array(vality.number)({
preprocess: val => {
try {
return JSON.parse(val as string);
} catch (e) {
return val;
}
}
}),
`["1",2,"3",4,5]`
); // { valid: true, data: [1,2,3,4,5] }

List of guards

Vality comes with 6 guards out of the box:

vality.string

Returns the value as a string. Accepts and casts string, number.

OptionAcceptsDefault ValueEffect
minLengthnumberundefinedMinimum length for the resulting string, inclusive (uses String.length)
maxLengthnumberundefinedMaximum length for the resulting string, inclusive (uses String.length)
matchRegExpundefinedRegular expression that needs to match the resulting string

vality.number

Returns the value as a number. Strings are parsed with parseFloat. Only accepts numbers in the safe integer range (this can be disabled with options).

OptionAcceptsDefault ValueEffect
minnumberundefinedMinimum value, inclusive
maxnumberundefinedMaximum value, inclusive
integerbooleanundefinedWhether the resulting number must be an integer
unsafebooleanfalseWhether to allow numbers outside the safe integer range

vality.boolean

Returns the value as a boolean. Accepts "1", 1, "true" for true, and "0", 0, "false" for false.

No options.

vality.date

Returns the value as a Date. Accepts Dates and anything Date.parse() can handle.

OptionAcceptsDefault ValueEffect
minDateundefinedMinimum value, inclusive
maxDateundefinedMaximum value, inclusive
pastbooleanundefinedWhether the date must lie in the past, excluding now
futurebooleanundefinedWhether the date must lie in the future, excluding now

literal => vality.literal

This guard is a little different. Other than the so far listed guards, this one is a guard factory, that creates a guard that returns and accepts only the given value.

ts
import { vality } from "vality";
 
validate(vality.literal(5), 5); // { valid: true }
ts
import { vality } from "vality";
 
validate(vality.literal(5), 5); // { valid: true }

Options are passed by simply calling the result from the factory:

ts
import { vality } from "vality";
 
validate(vality.literal(5)({ default: true }), undefined); // { valid: true }
ts
import { vality } from "vality";
 
validate(vality.literal(5)({ default: true }), undefined); // { valid: true }

No options.

However, the default option behaves differently here. As seen above, it accepts boolean values that simply indicate whether to use the literal value as the default value. (This is mainly to remove the need of writing the actual literal twice: once in the facory call, for the option.)

Parse<T>

Parse is used to represent a schema that is coming from the backend, an outgoing data structure.

vality.any

Returns the value as a unknown. Accepts any value except for undefined.

No options.