
Product
Rust Support Now in Beta
Socket's Rust support is moving to Beta: all users can scan Cargo projects and generate SBOMs, including Cargo.toml-only crates, with Rust-aware supply chain checks.
validate-structure
Advanced tools
Check that an object matches the expected structure.
npm i validate-structure
Note: Node 14+ is required.
Signature: validateStructure(val: any, structure: Structure, strict?: boolean, customTypes?: TypeDefs): ValidationError[]
Arguments:
val
The value to validate.structure
The expected structure of val
. This must be a
Structure.strict
Whether or not extra keys should be treated as
a failure (defaults to true
)customTypes
Any custom types that you want to refer to
multiple times can be placed here for convenience. This should be an object
where each key is the name of the type and the value is a
Structure.Signature: matchesStructure(val: any, structure: Structure, strict?: boolean, customTypes?: TypeDefs): boolean
This is a simple wrapper around validateStructure()
that returns true
if and
only if there were no errors returned by validateStructure()
. It can be used
if you only care that it doesn't match, but if you need to know what didn't
match you should use validateStructure()
directly.
validate-structure
is built around a robust type system, which means it can
handle any data structure you throw at it.
The most basic Structure is a single string representing a native type. The
following typeof
s are supported out-of-the-box:
"any"
(matches anything except null
and undefined
)"null"
"undefined"
(note that this still requires the key to be present)"boolean"
"number"
"bigint"
"string"
"symbol"
"function"
There are also some non-typeof
checks provided as well:
"int"
Matches any integer"array"
Matches any array"object"
Matches any object that is not an array or null
Sometimes you might find that just the basic types aren't enough. That's why
validate-structure
has a range of operators you can use to form complex
Structures.
"<type>?"
Optional: matches "<type>"
or null
or undefined
."<type>[]"
Array: matches an array of "<type>"
.
<type>[min...max]
<type>[min...]
<type>[...max]
min === max
) you can use the shorthand
form <type>[N]
<type>[1...]
or the
shorthand form <type>[.]
?
between the <type>
and the [
(like so: int?[]
)."[<type 1>, ..., <type n>]"
Tuple: matches an array of "<type>"
s with
strict length. For example, if you have an image size stored as a pair of
integers you can validate that with "[int, int]"
.<type 1> | ... | <type n>
Union: matches at least one of the "<type>"
s.(<type>)
Group: used to group types together. For instance the structure
(string | int)[]
will match an array where each item is either a string or
an integer.If your data can't be represented by one of the basic types you can use an object structure. It should exactly match the expected structure with a few exceptions:
'?'
to the key. For example:
{ 'optional?': 'string' }
.[]
,
[min...max]
, [min...]
, [...max]
, [.]
, and [N]
).
For example: { 'arr[]': 'string' }
.{ size: ["int", "int"] }
.If you have a complex type that you would like to reuse in multiple places you can specify it as a custom type. It also allows for recursion.
const types = {
Person: {
name: "Name",
"parents[]?": "Person",
"spouse?": "Person",
"children[]?": "Person",
},
Name: { first: "string", last: "string" },
};
validateStructure(person, "Person", true, types);
If you have a use case that is not satisfied by the aforementioned methods, you can write a custom validator function. These come in two flavors and can be used anywhere a Structure can.
Matcher (type MatcherFn = (val: any) => boolean
).
This is the simpler of the two. It takes in a value and should return true
if the value matches and false
if it doesn't.
Validator (type ValidatorFn = (val: any, path: string, types: TypeValidators, strict: boolean) => ValidationError[]
).
This is more complicated, but gives much more control. The arguments are as follows:
val
The value to validate.path
The keypath of the value in dot notation, used for error messages.types
A key:value map of other ValidatorFn
s. For example, types.array
is the ValidatorFn
that matches any array. This includes matchers for any
custom types you have defined.strict
Whether or not the validation is running in strict mode. See
validateStructure()
for details.The return type is an array of ValidationError
objects. Each
ValidationError
is an object consisting of three keys: msg
, path
, and
type
. msg
is a string explaining what the error is, path
is the path to
the invalid item, and type
is the type of the error. The default types are
"key"
, "val-start"
and "val-end"
, depending on where the mismatch was,
but any string may be used. Here is an example error:
{ msg: 'array must not be empty', path: ['arr'], type: "val-start" }
.
Here is an example to check if a value is a string that starts with a $
:
import type { ValidatorFn } from "validate-structure";
import { validateStructure, buildError } from "validate-structure";
const dollarString: ValidatorFn = (val, path, types, strict) => {
// Check if the value is a string
const errors = types.string(val, path, types, strict);
if (errors.length > 0) return errors;
// The value is fine, return no errors.
if (val.startsWith("$")) return [];
// The value is invalid, return an error
return buildError(`'${val}' does not start with a '$'`, path);
};
validateStructure("$12", dollarString); // -> []
validateStructure("12", dollarString); // -> [{msg: "'12' does not start with a '$'", path: ""}]
validateStructure({ price: "12" }, { price: dollarString }); // -> [{msg: "'12' does not start with a '$'", path: "price"}]
import { matchesStructure } from "validate-structure";
// A single string
matchesStructure("hello world", "string"); // -> true
// A single integer
matchesStructure(14, "int"); // -> true
matchesStructure(14.2, "int"); // -> false
// An array of numbers
matchesStructure([], "number[]"); // -> true
matchesStructure([14], "number[]"); // -> true
matchesStructure([1, 2, 3, 4, 5], "number[]"); // -> true
// A tuple of 2 numbers
const sizeTuple = "[number, number]"; // This could also be written "number[2]"
matchesStructure([1, 2], sizeTuple); // -> true
matchesStructure([1], sizeTuple); // -> false
matchesStructure([1, 2, 3], sizeTuple); // -> false
// A tuple of a string and an int
const ruleTuple = "[string, int]";
matchesStructure(["tabLength", 2], sizeTuple); // -> true
matchesStructure([14, 2], sizeTuple); // -> false
// A custom object structure
const structure = { id: "int", name: "string" };
matchesStructure({ id: 14, name: "John" }, structure); // -> true
// Strict mode is on by default
matchesStructure({ id: 14, name: "John" }, { id: "int" }); // -> false
matchesStructure({ id: 14, name: "John" }, { id: "int" }, false); // -> true
// Complex structures
const structure = {
name: "string",
tabs: {
name: "string",
"color?": "string",
"contents[.]": {
"title?": "string",
body: "string",
},
},
};
matchesStructure(
{
name: "Home",
tabs: {
name: "About",
contents: [
{ title: "About Us", body: "Lorem ipsum dolor sit amet" },
{ body: "consectetur adipiscing elit" },
],
},
},
structure
); // -> true
matchesStructure(
{
name: "Home",
tabs: {
name: "About",
contents: [],
},
},
structure
); // -> false (tabs.contents must be non-empty)
If you want to help out, please read the CONTRIBUTING.md.
2.0.0 (2021-06-23)
null
or
undefined
. To get the old behavior back, use 'any?' instead.FAQs
Check that an object matches the expected structure.
We found that validate-structure demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket's Rust support is moving to Beta: all users can scan Cargo projects and generate SBOMs, including Cargo.toml-only crates, with Rust-aware supply chain checks.
Product
Socket Fix 2.0 brings targeted CVE remediation, smarter upgrade planning, and broader ecosystem support to help developers get to zero alerts.
Security News
Socket CEO Feross Aboukhadijeh joins Risky Business Weekly to unpack recent npm phishing attacks, their limited impact, and the risks if attackers get smarter.