I highly recommend reading this with full Typescript support in the code-snippets

tsx.md/github.com/robolex-app/public_ts/blob/main/README.md

Headless Type-safe validation library for Javascript

As with other validation libaries like zod, yup, io-ts, superstruct, valibot, etc...

You can easily validate any value using:

Loading...

What this library does differently is that it puts the focus on customization and makes the core so simple, that you can define your string validator like this:

Loading...

This is actually how the string from the initial example is defined.

Why a new library?

I've written a lengthy article about the problems I've encountered while trying to validate a simple form, and not wanting to get forced into some custom strane DSL.

It's a good read, I promise.

tsx.md/blog/valid_form

The gist of it is that validating a value as string or number is easy in any of the aforementioned libraries.

What's not easy, is validating an IBAN using validator.js, or validating an IBAN, but showing different error messages for countries whose IBAN your SaaS doesn't currently support, but will support in the next quarter.

If you want to do this in zod, you'll have to understand the difference between refine https://zod.dev/?id=refine superRefine https://zod.dev/?id=superrefine transform https://zod.dev/?id=transform

You'll also encounters lots of interesting issues related to how these 3 methods combine with each other.

Type for the errors

The type of which type of "errors" you can receive is usually not enforced.

This library takes a different approach and considers errors as first class citizens. That was the main reason the function bad isn't called error since it's not something I like to throw, it's something I want to know and understand.

The core library in this:

./esm/core.js

Loading...

Everything else is based on the core types and those 4 functions.

Custom validators:

If you want to validate that something is an IBAN you can just define a function:

Loading...

Common utilities:

Of course, there are the basic utilities, for things you'd expect from other type-safe libraries:

primitives

/packages/sure/esm/primitives.js

The library doesn't provide too many primitives, the idea being, that you already know how to check if something is a string.

Other libraries have lots of different views about what a string is (empty or not), or what a number is (NaN or infinity).

Usually I want to validate if something is a positive integer, or if something is a valid age. In that case I just write a function, that's all.

Nevertheless, there are currently several primitives:

Loading...

object and optional

/packages/sure/esm/object.js

Loading...

array

/packages/sure/esm/array.js

Loading...

after

This is the refine function from zod, but it's much simpler to use. It runs the first validator, and if it's successful, it runs the second validator. It returns the first bad value it encounters.

Loading...

Other utilities

tuple

/packages/sure/esm/tuple.js

Loading...

literal

/packages/sure/esm/literal.js

Loading...

union = or

/packages/sure/esm/union.js

Loading...

Advanced utilities

intersection = and

/packages/sure/esm/intersection.js

Currently and (which is a different name for intersection) works only on objects, since I use object destructuring when returning the final value.

Loading...

recursive

The recursive function is a bit more complex, basically, you have an object and you can say that one of the fields is expected to be recursive.

Afterwards you can use the recurse function to define the shape of the recursive element.

The idea here is that it's not possible to know the shape of the recursive element before you define the object that contains it.

This was implemented mostly to test the limits of the library.

Loading...

The meta property in the validation function

Things like object that return another function which is the actual validator, can have data that's attached to them.

At the moment I don't personally use this feature.

They were added to allow introspection of the validation schema in cases where it might be necessary to

Decided how to store any metadata was a tought decision, especially when validators are simple functions.

The meta is a property that can be directly set to a function.

Loading...

This type tells us that a function can either NOT have a meta property, or it can have meta property that you don't know the type of.

This idea can be applied to any function whatsoever, since any function can either have a meta property or not. Most functions don't.

This seemed like the less invasive option.