Superstruct is a simple data validation library that checks your data while your app runs. When you get data from APIs, user forms, or anywhere else, you can't always trust it. Superstruct helps you make sure the data looks exactly like you expect.
You can think of Superstruct as a guard for your application. It stops bad data before it breaks your code. The library works great with TypeScript and gives you clear error messages when something goes wrong.
This guide shows you how to use Superstruct in your TypeScript projects. You'll learn how to create validation rules, check different types of data, handle errors, and use Superstruct in real applications.
Let's get started!
Prerequisites
You need Node.js and npm installed on your computer before you start. You should also know the basics of TypeScript since this guide assumes you understand TypeScript syntax.
Setting up the development environment
First, you'll set up a TypeScript project that can run your code directly without building it first. This makes development faster and easier.
Create a new folder for your project:
Start a new npm project:
Tell npm to use ES modules:
Install Superstruct and the TypeScript tools you need:
Here's what each tool does:
typescript: The main TypeScript compilertsx: Runs TypeScript files directly without compiling them first
Create your TypeScript config file:
Update your tsconfig.json to use ES2022 or higher to avoid compatibility issues:
The ES2022 target ensures compatibility with modern JavaScript features while avoiding issues with async/await and other features that Superstruct relies on.
Add a script to your package.json to run your project easily:
Your TypeScript setup is ready. You can write Superstruct code and test it right away.
Understanding Superstruct fundamentals
Superstruct uses functions to define what your data should look like. You combine these functions to create validation rules that check your data automatically.
Create a file called schemas.ts with your first validation schema:
This schema tells Superstruct that a person object must have:
firstNameas a stringlastNameas a stringageas a number
Each validation rule is a function. You can mix and match these functions to create complex validation logic.
Now create your main index.ts file to test the validation:
The create() method checks your data against the schema. If the data is valid, it returns the data. If not, it throws an error with details about what went wrong.
Run your code:
You'll see this output with valid data:
This shows the basic Superstruct workflow: define schemas with functions, then validate data with the schema's methods.
Building advanced validation schemas
Superstruct gives you many ways to validate data beyond just checking types. You can add length requirements, format checks, and custom rules that fit your specific needs.
Adding string constraints
Most string fields need more than just type checking. Superstruct has built-in validators for common string requirements.
Update your schemas.ts file to include more detailed validations:
Each validator adds a specific rule:
size(string(), 3, 20): Username must be 3-20 characters longpattern(string(), /^[^\s@]+@[^\s@]+\.[^\s@]+$/): Email must match a valid email patternsize(string(), 8, 50): Password must be 8-50 characters longpattern(string(), regex): Phone number must match the pattern
Test these rules with invalid data. Update your index.ts file:
In the highlighted code, you're importing the validation schema, creating an object with intentionally invalid data, and attempting to validate it using UserSchema.create(). If the validation fails, the code catches the error and logs a helpful message to the console, making it easy to see which fields didn't pass the validation rules.
Run this code:
You'll get a clear error message:
Superstruct tells you exactly which field failed and why, making it easy to fix problems.
Creating custom validation functions
You can write your own validation functions for special requirements that the built-in validators don't cover.
Add a custom password validator to your schemas.ts:
The define function creates custom validators. Return true if the data is valid, or return an error message string if it's not. This gives you complete control over your validation logic.
Test the strong password requirement by updating your test data:
When you run the program, the validation will fail with:
Combining multiple validation rules
You can also chain multiple validations together by creating more complex schemas. This allows you to build sophisticated validation logic step by step.
Update your schemas.ts to include nested validation:
This nested structure shows how Superstruct handles complex objects:
AddressSchemavalidates address components separatelyoptional()makes phone number not requiredarray(string())ensures hobbies is a list of stringszipCodeuses a regex pattern for US zip codes
Test the nested validation with complete data:
Now when you run the code with valid data:
You'll see successful validation:
And in the console, it might look something like this:
The output is well-formatted, and certain elements, such as strings, numbers, and keys, are color—coded, making it easier to read and identify details quickly.
This demonstrates how you can build complex validation schemas by combining simple validation functions. Each piece handles one concern, making your validation logic easy to understand and maintain.
Handling validation errors gracefully
Superstruct gives you detailed information about validation failures. You can use this information to debug problems and show helpful messages to users.
Understanding Superstruct error structure
When validation fails, Superstruct creates error objects that tell you exactly what went wrong and where the problem occurred.
Create a new file to explore error handling:
In this code, you're creating data with multiple validation problems, then examining the error object's properties to understand what information Superstruct provides when validation fails.
Run this code:
You'll see detailed error information:
StructError objects give you structured information about validation failures. You can see which field failed, what value caused the problem, and get a human-readable description.
Collecting multiple validation errors
By default, Superstruct stops at the first error it finds. You can collect all errors at once using the validate method instead of create.
Update your error handling file:
The validate method returns a tuple with either an error or the validated result. The failures() method gives you every validation error in your data, so you can show users all the problems at once instead of making them fix one error at a time.
Run the updated code:
You'll see all validation errors listed:
Creating user-friendly error messages
Raw Superstruct errors can be too technical for regular users. You can create helper functions to make the messages more friendly and actionable.
Add a formatting function to your error handling file:
This formatting function converts technical error messages into language that regular users can understand. You keep the structured format you need for forms and APIs, but make the messages much clearer.
Run the code with friendly error formatting:
You'll see much more user-friendly error messages:
This approach transforms technical validation messages into language that regular users can understand, while maintaining the structured format needed for form validation or API responses.
Final thoughts
This guide showed you how to use Superstruct for data validation in TypeScript projects. You learned to create schemas, add custom rules, handle errors, and make error messages user-friendly.
Superstruct's functional approach makes it easy to build complex validation from simple parts, while TypeScript integration keeps your code type-safe automatically.
You're now ready to add solid data validation to your applications. For advanced features and complete API details, check the official Superstruct documentation.
Start with basic schemas and build up to more complex validation as your app grows. Good validation is one of the best ways to make your application reliable and user-friendly.