- Notifications
You must be signed in to change notification settings - Fork2
TypeScript runtime type validator generator that creates validation functions from TypeScript types with custom validation rules defined using JSDoc comments.
License
donflopez/ttype-safe
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
TypeSafe is a TypeScript library that generates runtime validation rules from your code's TypeScript types. It analyzes your type definitions at build time and creates validators for validating data structures at runtime, ensuring they conform to expected types. You can add custom rules to types using JSDoc comments with tags like @regex and @max. It's easy to integrate with your TypeScript workflow and supports complex nested types like arrays and tuples. It helps create more reliable applications with less effort and fewer errors.
WARNING: This library is under heavy development, many features are still missing and the API will change as I explore what is the most developer friendly way to secure your types. You should expect changes in the main apis and tags used to add validation rules.
Zod the lead of this type of tools, while in spirit both ttype-safe and zod aim for the goal the approaches are radically different. Zod exposes a series of methods thatallows you to build validators and extract the types from these. TTS aims to offer the native TS experience when building types and with the support of jsdocs allow you to use validation rules with minimal effort.
A zod example:
constUser=z.object({username:z.string().min(3).max(10),});User.parse({username:'no'})// throwsUser.parse({username:'valid'})// passes// To get and use the type you need to.typeUser=z.infer<typeofUser>;
A TTS example:
typeUser={/** * Name of the user to use in the application. This has to be unique and cannot be changed once saved. * *@min 3 *@max 10 */username:string}constƒUser=validate<User>($schema<User>());ƒUser({username:'no'})// falseƒUser({username:'valid'})// true
TTS has several advantages:
- You keep the native type experience, so you don't need to learn how to create types with Zod and you get typechecking out of the box without using comments, all type validators that you create will check primitives like number, string, boolean.
- Working with generics and complex types just works, again you don't need to learn how to work with generics.
- Comment tags that add validation rules can be customized and reused, you don't need to import them. You just need to pass your custom validator.
- This is the most important one, you can comment your types and generate automatic documentation with ts docs. I'm working on a plugin that will include a tag definition as validation rules sodocumentation of your rules is for free.
You can find a working example project here
"devDependencies": {"ts-patch":"3.1.2","ttype-safe":"^0.6.0"},"scripts": {..."prepare":"ts-patch install -s",...}
Configuringts-patch
To use tType-Safe withts-patch, you need to add the following to yourtsconfig.json file:
{"compilerOptions": {"moduleResolution":"node16",// or NodeNext"plugins": [ {"transform":"ttype-safe" } ] }}And then you need to build your project withttsc instead oftsc.
How to create validators:
import{$schema,validate}from"ttype-safe/validate";// Define your TypeScript types with custom validation rules using JSDoc commentstypePerson={/** * The name property must be a string with at least 2 characters *@min 2 */name:string;/** * The age property must be a number between 0 and 120 *@min 0 *@max 120 */age:number;/** * The email property must be a string that contains an '@' character *@regex /@/ */email:string;};// Create a validator function for the Person typeexportconstPersonValidator=validate<Person>($schema<Person>());
Your compiled code will replace$schema with the generated validation rules extracted from your TypeScript types and TsDoc comments. Thevalidate function will create a validator function that will validate the data structure at runtime.
You can create custom tags for primitive types, like @max or @regex but. In the following example we're going to create a tag for dates:
constvalidate=createCustomValidate({string:{date:(value:string):boolean=>{returnnewRegExp(/^\d{4}-\d{2}-\d{2}$/).test(value);}}});typePerson={/** *@date */birthday:string;};constPersonValidator=validate<Person>($schema<Person>());PersonValidator({birthday:"2021-01-01"});// goodPersonValidator({birthday:"2021-01-01T00:00:00"});// bad
constvalidate=createCustomValidate({string:{date:(value:string):boolean=>{returnnewRegExp(/^\d{4}-\d{2}-\d{2}$/).test(value);}}},true);// Pass true to throw instead of returning falsetypePerson={/** *@date */birthday:string;};constPersonValidator=validate<Person>($schema<Person>());PersonValidator({birthday:"2021-01-01"});// goodPersonValidator({birthday:"2021-01-01T00:00:00"});// Throws -> ValidationError: Tag validation [date] and comment [null] didn't succeed for value [2021-01-01T00:00:00]
Note: This is only supported with ts-jest v29 or higher.
To use Type-Safe with jest, you need to add the following to yourjest.config.js and use ts-jest file:
// Package.json"jest": {"transform": {"^.+\\.tsx?$": ["ts-jest", {"astTransformers": {"before": ["ttype-safe" ] } } ] } }
import{$schema,validate}from"ttype-safe/validation";// Define your TypeScript types with custom validation rules using JSDoc commentstypePerson={/** * The name property must be a string with at least 2 characters *@min 2 */name:string;/** * The age property must be a number between 0 and 120 *@min 0 *@max 120 */age:number;/** * The email property must be a string that contains an '@' character *@regex /@/ */email:string;};// Create a validator function for the Person typeexportconstPersonValidator=validate<Person>($schema<Person>());// Test the validator function with sample dataconstvalidPerson={name:"John",age:35,email:"john@example.com"};constinvalidPerson={name:"J",age:150,email:"invalid-email"};console.log(PersonValidator(validPerson));// goodconsole.log(PersonValidator(invalidPerson));// bad
typeCar={/** *@regex /\d[A-Z]{3}\d{3}/ */plate:string;}constCarValidator=validate<Car>($schema<Car>());CarValidator({plate:"1ABC123"});// goodCarValidator({plate:"1ABC12"});// bad
typeCar={/** *@alphanumeric */plate:string;}constCarValidator=validate<Car>($schema<Car>());CarValidator({plate:"1ABC123"});// goodCarValidator({plate:"1ABC12#"});// bad
typeCar={/** *@min 3 */plate:string;}constCarValidator=validate<Car>($schema<Car>());CarValidator({plate:"1ABC123"});// goodCarValidator({plate:"1A"});// bad
typeCar={/** *@max 3 */plate:string;}constCarValidator=validate<Car>($schema<Car>());CarValidator({plate:"1ABC123"});// goodCarValidator({plate:"1ABC1234"});// bad
typePerson={/** *@email */email:string;}constEmailValidator=validate<Person>($schema<Person>());EmailValidator({email:"John1988@gmail.com"});// goodEmailValidator({email:"myEmail"});// bad
typePerson={/** *@notempty */firstName:string;}constNotemptyValidator=validate<Person>($schema<Person>());NotemptyValidator({firstName:"John"});// goodNotemptyValidator({firstName:""});// bad
typeHuman={/** *@min 0 */age:number;}constHumanValidator=validate<Human>($schema<Human>());HumanValidator({age:0});// goodHumanValidator({age:-1});// bad
typeHuman={/** *@max 100 */age:number;}constHumanValidator=validate<Human>($schema<Human>());HumanValidator({age:100});// goodHumanValidator({age:101});// bad
- Type Aliases jsdoc tags are not supported yet:
/** *@min 0 *@max 100 */typeAge=number;// Doesn't work yet, it will only validate the type as a number but no// the min and max tagsconstAgeValidator=validate<Age>($schema<Age>());
- BigInt is not supported and tags will be ignored:
typeHuman={/** *@min 0 */age:bigint;}// This will do nothing, nor validate the type nor the tags.constHumanValidator=validate<Human>($schema<Human>());
- Symbol is not supported and tags will be ignored:
typeHuman={/** *@min 0 */age:symbol;}// This will do nothing, nor validate the type nor the tags.constHumanValidator=validate<Human>($schema<Human>());
- Functions are not supported and will probably never be supported;
typeHuman={/** *@min 0 */age:()=>void;}// This will do nothing, nor validate the type nor the tags.constHumanValidator=validate<Human>($schema<Human>());
About
TypeScript runtime type validator generator that creates validation functions from TypeScript types with custom validation rules defined using JSDoc comments.
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.