prover-ts v1.2.1
Prover-ts
Prover-ts is a small lightweight package to parse through unknown shapes, providing strong typing.
Installation
npm install prover-tsUsage
import { prover } from "prover-ts";
/*
* API returns an object. A familiar shape is known, but strong confirmation is needed.
* Prover-ts can help on that.
*/
try {
const unknownShape = await fetchingSomething(); // unknown
const parsedShape = prover
.object({ name: prover.string(), lastName: prover.string(), age: prover.number() })
.parse(unknownShape);
} catch (error) {
console.log(error);
}parsedShape
would be typed like this:
const parsedShape: {
name: string;
lastName: string;
age: number;
};prover-ts would return an error if the object did not match the expected shape. Future releases might change this.
Supported types
String
nonEmptyexpects a non-empty string.
const result = prover.string().nonEmpty().parse("Test"); // Throws prover.string().nonEmpty().parse("");
maxParameters
maxLength {number}expected max charactersconst result = prover.string().max(5).parse("Hello"); // Throws prover.string().max(5).parse("Hello World");
minParameters
minLength {number}expected min charactersconst result = prover.string().min(5).parse("Hello"); // Throws prover.string().min(5).parse("Hi");
lengthParameters
length {number}expected string lengthconst result = prover.string().length(5).parse("Hello"); // Throws prover.string().length(5).parse("Hello again");
includesParameters
toInclude {string}expected string to be presentconst result = prover.string().includes("Hello").parse("Hello World"); // Throws prover.string().includes("Hello").parse("Hi World");
startsWithParameters
toStartWith {string}expected characters matching the beginning of the stringconst result = prover.startsWith("Hello").parse("Hello, world!"); // Throws prover.startsWith("Hello").parse("Hi, world!");
endsWithParameters
endsWith {string}expected characters matching the end of the stringconst result = prover.endsWith("world!").parse("Hello, world!"); // Throws prover.endsWith("world!").parse("Hello, universe!");
regexParameters
pattern {string | RegExp}pattern to matchconst result = prover.regex(/^\d{4}$/).parse("1234"); // Throws prover.regex(/^\d{4}$/).parse("12345");
emailexpects an email
const result = prover.email().parse("test@gmail.com"); // Throws prover.email().parse("invalid-email");
dateexpects a date formatted yyyy-mm-dd
const result = prover.date().parse("2023-05-30"); // Throws prover.date().parse("30/05/2023");future implementation might support different formats
numericexpects a numeric string
const result = prover.numeric().parse("12345"); // Throws prover.numeric().parse("abc12345");
alphanumericexpects an alphanumeric string
const result = prover.alphanumeric().parse("abc123"); // Throws prover.alphanumeric().parse("abc@123");
ipv4expects an ipv4 matching string
const result = prover.ipv4().parse("192.168.0.1"); // Throws prover.ipv4().parse("256.256.256.256");
funcParameters
predicate {(arg: string) => boolean}predicate function responsible to validate stringconst isUpperCase = (arg: string) => arg === arg.toUpperCase(); const result = prover.func(isUpperCase).parse("HELLO"); // Throws prover.func(isUpperCase).parse("Hello");
Number
positiveexpects a positive number.
const result = prover.number().positive().parse(1); // Throws prover.number().positive().parse(-1);
negativeexpects a negative number.
const result = prover.number().negative().parse(-1); // Throws prover.number().negative().parse(1);
equaltoEqual {number}expects an equal number.const result = prover.number().equal(42).parse(42); // Throws prover.number().equal(42).parse(-1);
gtParameters
comp {number}number to be greater thanconst result = prover.number().gt(42).parse(69); // Throws prover.number().gt(42).parse(22);
gteParameters
comp {number}number to be greater or equal thanconst result = prover.number().gte(42).parse(42); // Throws prover.number().gte(42).parse(24);
ltParameters
comp {number}number to be lesser thanconst result = prover.number().lt(42).parse(24); // Throws prover.number().lt(42).parse(69);
lteParameters
comp {number}number to be lesser or equal toconst result = prover.number().lte(42).parse(42); // Throws prover.number().lte(42).parse(69);
multipleParameters
comp {number}number to be multiple ofconst result = prover.number().multiple(5).parse(10); // Throws prover.number().multiple(3).parse(10);
saveRequires number to be a safe integer, meaning, between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER
const result = prover.number().save().parse(10); // Throws prover.number().save().parse(Infinity);
finiteRequires number to be in between Infinity and -Infinity
const result = prover.number().finite().parse(69); // Throws prover.number().finite().parse(Infinity);
funcParameters
func {(arg: number) => boolean}predicate function responsible to validate numberconst isEven = (arg) => arg % 2 === 0; const result = prover.number().func(isEven).parse(10); // Throws prover.number().func(isEven).parse(3);
Object
safefilters out unexpected properties
const result = prover .object({ name: prover.string().nonEmpty(), age: prover.number().positive() }) .safe() .parse({ name: "John", age: 30, address: ["street 1", "street 2"] });Without calling safe(), result object would have a
addressproperty, since prover's default behavior would NOT filter out a property that was not expected to exist.
Other examples
const result = prover .object({ name: prover.string().nonEmpty(), age: prover.number().positive() }) .parse({ name: "John", age: 30 });const result = prover .object({ name: prover.string().nonEmpty(), idNumber: prover.number().positive(), married: prover.boolean(), address: prover.array(prover.string()), }) .parse({ name: "John", idNumber: 12131313, married: true, address: ["hollywood, beverly hills"] });Inferred correctly
const result: { name: string; idNumber: number; married: boolean; address: string[] };
Record
When you only care about the values and their types
Examples
const result = prover.record(prover.string()).parse({ name: "John", lastName: "Doe" }); // Throws prover.record(prover.string()).parse({ name: "John", age: 30 });
Array
maxParameters
{nElements}number of max elements that should be inside the arrayconst result = prover.array([prover.number()]).max(10).parse([1, 2, 3, 4, 5, 6]); // Throws prover.array([prover.number()]).max(2).parse([1, 2, 3, 4, 5, 6]);
minParameters
{nElements}number of min elements that should be inside the arrayconst result = prover.array([prover.number()]).min(2).parse([1, 2, 3, 4, 5, 6]); // Throws prover.array([prover.number()]).min(10).parse([1, 2, 3, 4, 5, 6]);
sizeParameters
{nElements}number of exact elements that should be inside the arrayconst result = prover.array([prover.number()]).size(6).parse([1, 2, 3, 4, 5, 6]); // Throws prover.array([prover.number()]).size(10).parse([1, 2, 3, 4, 5, 6]);
nonEmptyconst result = prover.array([prover.number()]).nonEmpty().parse([1, 2, 3, 4, 5, 6]); // Throws prover.array([prover.number()]).nonEmpty().parse([]);Other Examples
const result = prover.array([prover.number(), prover.string()]).parse([1, 2, "3", 4, "5", 6]); // Throws prover.array([prover.number(), prover.string()]).parse([1, 2, "3", 4, "5", 6, true]);Inferred correctly
const result: (string | number)[];
Tuple
Examples
prover.tuple([prover.number(), prover.number(), prover.boolean()]).parse([1, 2, true]); // Throws prover.tuple([prover.number(), prover.number(), prover.boolean()]).parse([1, "2", true]);
Record and Tuple are still experimental features.
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
Make sure to include changeset.