@zcabjro/vivalidate is a validation library written in typescript that focuses on being small and easy to use. Using simple primitives like
string
andobject
, you can build complex schemas and then validate incoming data at runtime while getting type declarations for free in the process.
Prior to v0.8.0, we could already get some mileage out of extracting common shapes from a schema to avoid unnecessary duplication.
const meta = v.object({
title: v.string(),
tags: v.array(v.string()),
created: v.number(),
});
const post = v.object({
id: v.string(),
meta,
...otherPostFields,
});
const project = v.object({
id: v.string(),
meta,
...otherProjectFields,
});
This saves us some typing but we were lacking a way to simply extend a given schema. For example, imagine if post
and project
were actually almost identical except that projects contain some information about project members. Suppose also that the meta fields actually belonged on the top-level instead of being nested under meta
:
const post = v.object({
id: v.string(),
title: v.string(),
tags: v.array(v.string()),
created: v.number(),
});
const project = v.object({
id: v.string(),
title: v.string(),
tags: v.array(v.string()),
created: v.number(),
members: v.array(v.string()),
});
If we knew that the commonality between post
and project
was there to stay then we might resent having to duplicate the fields across both schemas. In v0.8.0, vivalidate introduces and
for extending (intersecting) schemas. With it, we can shrink the above to just:
const post = v.object({
id: v.string(),
title: v.string(),
tags: v.array(v.string()),
created: v.number(),
});
const project = post.and(
v.object({
members: v.array(v.string()),
}),
);
The resulting validator runs a given value through both post
and the argument validator. As long as it satisfies both, then the result is typed as the intersection of the two inferred types. If either one fails to validate, then the result contains a concatenation of errors.