Types

Superstruct exposes factory functions for a variety of common JavaScript (and TypeScript) types. You can also define your own custom validation functions using the struct factory.

any

any()
'valid'
42
true
undefined
null
{
also: 'valid'
}

any structs accept any value as valid.

🤖 Note that if you're using TypeScript, the any struct will loosen the type to any, and you might want to use unknown instead.

array

array(number())
array(object({ id: number() }))
[1, 2, 3]
[{ id: 1 }]

array structs accept a list of values of a specific type.

boolean

boolean()
true
false

boolean structs accept the boolean values true and false.

date

date()
new Date()

date structs accept JavaScript Date instances.

🤖 To avoid unexpected runtime errors, date structs do not accept invalid Date objects, even though they are technically an instance of a Date. This meshes with the 99% use case where invalid dates create inconsistencies.

enums

enums(['Jane', 'John', 'Jack', 'Jill'])
'Jane'
'John'

enums structs validate that a value is one of a specific set of literals values.

func

func()
function () {}

func structs validate that a value is a function.

instance

instance(MyClass)
new MyClass()

instance structs validate that a value is an instance of a particular class, using JavaScript's built-in instanceof operator.

integer

integer()
-7
0
42

integer structs validate that a value is an integer.

intersection

intersection([string(), Email])

intersection structs validate that a value matches all of many structs. It takes existing struct objects as arguments.

literal

literal(42)
42

literal structs enforce that a value matches an exact value using the === operator.

map

map(string(), number())
new Map([
['a', 1],
['b', 2],
])

map structs validate that a value is a Map object with specific types for its keys and values.

🤖 When defining a key/value schemas with map it will traverse all the properties to ensure they are valid! If you don't care about validating the properties of the map, you can write map() instead.

never

never()

never structs will fail validation for every value.

number

number()
0
3.14
42
Infinity

number structs validate that a value is a number.

nullable

nullable(string())
'a string of text'
null

nullable structs validate that a value matches a specific struct, or that it is null.

object

struct({
id: number(),
name: string(),
})
{
id: 1,
name: 'Jane Smith',
}

object structs validate that a value is an object and that each of its properties match a specific type as well.

🤖 Note that object structs throw errors if they encounter extra properties on an object, unless mask is used! If you want to be less strict and ignore any extra properties, use type instead. For other more complex object use cases, check out the coercions and utilities too.

optional

optional(string())
'a string of text'
undefined

optional structs validate that a value matches a specific struct, or that it is undefined.

record

record(string(), number())
{
a: 1,
b: 2,
}

record structs validate an object with specific types for its keys and values. But, unlike object structs, they do not enforce a specific set of keys.

regexp

regexp()
;/\d+/
new RegExp()

regexp structs validate that a value is a RegExp object.

🤖 This does not test the value against the regular expression! For that you want the pattern refinement.

set

set(string())
new Set(['a', 'b', 'c'])

set structs validate that a value is a Set instance with elements of a specific type.

🤖 When defining a child schema with set it will traverse all the children to ensure they are valid! If you don't care about validating the elements of the set, you can write set() instead.

string

string()
'a string of text'

string structs validate that a value is a string.

tuple

tuple([string(), number(), boolean()])
['a', 1, true]

tuple structs validate that a value is an array of a specific length with values each of a specific type.

type

type({
name: string(),
walk: func(),
})
{
name: 'Jill',
age: 37,
race: 'human',
walk: () => {},
}

type structs validate that a value has a set of properties on it, but it does not assert anything about unspecified properties. This allows you to assert that a particular set of functionality exists without a strict equality check for properties.

When mask() is used with a value of type, its unknown properties are not removed. I.e. consider type as a signal to the core that the object may have arbitrary properties in addition to the known ones, in both masked and non-masked validation.

🤖 If you want to throw errors when encountering unknown properties, use object instead.

union

union([string(), number()])
'a string'
42

union structs validate that a value matches at least one of many types.

unknown

unknown()
'valid'
42
true
undefined
null
{
also: 'valid'
}

unknown structs accept unknown value as valid without loosening its type to any.

Custom Types

You can also define your own custom structs that are specific to your application's requirements, like so:

import { define } from 'superstruct'
import isEmail from 'is-email'
import isUuid from 'is-uuid'
const Email = define('Email', isEmail)
const Uuid = define('Uuid', (value) => isUuid.v4(value))
const User = object({
id: Uuid,
name: string(),
email: Email,
age: number(),
})

Custom types take validator functions that return either true/false or an array of StructFailure objects, in case you want to build more helpful error messages.