Superstruct makes it easy to define interfaces and then validate JavaScript data against them. Its type annotation API was inspired by TypeScript, Flow, Go, and GraphQL, giving it a familiar and easy to understand API.
But Superstruct is designed for validating data at runtime, so it throws (or returns) detailed runtime errors for you or your end users. This is especially useful in situations like accepting arbitrary input in a REST or GraphQL API. But it can even be used to validate internal data structures at runtime when needed.
Usage
Superstruct allows you to define the shape of data you want to validate:
import { assert, object, number, string, array } from'superstruct'constArticle=object({ id:number(), title:string(), tags:array(string()), author:object({ id:number(), }),})constdata= { id:34, title:'Hello World', tags: ['news','features'], author: { id:1, },}assert(data, Article)// This will throw an error when the data is invalid.// If you'd rather not throw, you can use `is()` or `validate()`.
Superstruct ships with validators for all the common JavaScript data types, and you can define custom ones too:
import { is, define, object, string } from'superstruct'import isUuid from'is-uuid'import isEmail from'is-email'constEmail=define('Email', isEmail)constUuid=define('Uuid',isUuid.v4)constUser=object({ id: Uuid, email: Email, name:string(),})constdata= { id:'c8d63140-a1f7-45e0-bfc6-df72973fea86', email:'jane@example.com', name:'Jane',}if (is(data, User)) {// Your data is guaranteed to be valid in this block.}
Superstruct can also handle coercion of your data before validating it, for example to mix in default values:
import { create, object, number, string, defaulted } from'superstruct'constUser=object({ id:defaulted(number(), () =>1), name:string(),})constdata= { name:'Jane',}// You can apply the defaults to your data while validating.constuser=create(data, User)// {// id: 1,// name: 'Jane',// }
And if you use TypeScript, Superstruct automatically ensures that your data has proper typings whenever you validate it:
import { is, object, number, string } from'superstruct'constUser=object({ id:number(), name:string()})constdata:unknown= { ... }if (is(data, User)) {// TypeScript knows the shape of `data` here, so it is safe to access// properties like `data.id` and `data.name`.}
Superstruct supports more complex use cases too like defining arrays or nested objects, composing structs inside each other, returning errors instead of throwing them, and more!