Superstruct Data Validation
Superstruct is a robust and composable library for validating data in JavaScript and TypeScript, designed to provide a simple yet powerful way to define data schemas and enforce their integrity. Currently stable at version 2.0.2, the library maintains an active release cadence, frequently publishing patches to address type resolution, minor bugs, and improve compatibility, as seen with recent 2.0.x releases. Its core differentiator lies in its idiomatic JavaScript API, making it easy to define complex data structures using plain objects and functions, rather than relying on class-based or decorator-heavy approaches. Superstruct focuses on clear error reporting and type inference, integrating seamlessly into TypeScript projects to provide compile-time type safety alongside runtime validation. It's particularly useful in API development, configuration parsing, and any scenario requiring reliable data ingress.
Common errors
-
TypeError: require is not a function
cause Attempting to use CommonJS `require()` syntax in an ESM module context, or when the `superstruct` package is treated as an ESM module.fixMigrate your import statements to ES Modules syntax: `import { object } from 'superstruct'`. If you are in a Node.js CJS module, you may need to ensure your `package.json` specifies `"type": "commonjs"` and potentially configure your build system for interop. -
TS2307: Cannot find module 'superstruct' or its corresponding type declarations.
cause TypeScript compiler cannot locate the package or its types, often due to incorrect module resolution settings, or an outdated TypeScript version that doesn't fully support NodeNext module features.fixVerify `superstruct` is installed. Check your `tsconfig.json` for `moduleResolution` (e.g., `"node16"` or `"bundler"`) and `module` (e.g., `"esnext"` or `"nodenext"`). Ensure your TypeScript version is up-to-date (>=4.7 for NodeNext features). -
StructError: At path "age" expected a number but received "twenty-five"
cause A runtime validation error indicating that a value for a specific path in the data does not match the expected type defined in the Superstruct schema.fixInspect the `error.path` and `error.value` properties of the `StructError` to identify the problematic data point. Adjust the input data to conform to the schema's type expectations, or modify the schema if the data structure has genuinely changed.
Warnings
- breaking Superstruct v2.0.0 introduced a fix for incorrectly passing validation for arrays within `object()`, `type()`, and `record()` structs. If you were relying on the previous, incorrect behavior where invalid arrays might have been accepted, your validation logic will now correctly flag these as errors.
- gotcha Superstruct has progressively moved towards stricter module resolution, especially with 'NodeNext' compatibility. Version 1.0.5-0 (pre-v2) explicitly added file extensions to imports/exports, indicating a shift towards explicit ESM module graphs. This can lead to issues with CommonJS setups or misconfigured TypeScript projects.
- gotcha With NodeNext type resolution, users migrating or using Superstruct in CommonJS environments might encounter TypeScript errors related to type declaration files (`d.cts`). Versions 2.0.3-0 and 2.0.3-1 specifically address fixes for these scenarios.
Install
-
npm install superstruct -
yarn add superstruct -
pnpm add superstruct
Imports
- object
const { object, string, number } = require('superstruct')import { object, string, number } from 'superstruct' - assert
import assert from 'superstruct/assert'
import { assert, StructError } from 'superstruct' - Struct
import { Struct } from 'superstruct'import type { Struct } from 'superstruct'
Quickstart
import { object, string, number, array, assert, StructError } from 'superstruct';
// Define a struct for a User
const User = object({
id: string(),
name: string(),
email: string(),
age: number(),
roles: array(string()),
});
// Example valid data
const validUser = {
id: 'user-123',
name: 'John Doe',
email: 'john.doe@example.com',
age: 30,
roles: ['admin', 'editor'],
};
// Example invalid data
const invalidUser = {
id: 'user-456',
name: 'Jane Smith',
email: 'jane.smith@example.com',
age: 'twenty-five', // Age should be a number
roles: ['viewer', 123] // Roles should be array of strings
};
console.log('Validating validUser...');
try {
assert(validUser, User);
console.log('validUser is valid!');
} catch (error) {
if (error instanceof StructError) {
console.error('Validation failed for validUser:', error.message);
} else {
throw error;
}
}
console.log('\nValidating invalidUser...');
try {
assert(invalidUser, User);
console.log('invalidUser is valid (this should not happen)!');
} catch (error) {
if (error instanceof StructError) {
console.error('Validation failed for invalidUser:', error.message);
console.error('Failure path:', error.path);
} else {
throw error;
}
}