Back to blog

Validation

Published: 2024-02-01T13:57:04Z

Updated: 2024-02-01T15:17:26Z

Validation Libraries

Validation libraries in JavaScript have recently had a surge in popularity. In my opinion it was lead by zod, followed by valibot. Now a new challenger has emerged: ArkType.

Zod

Zod utilizes chaining to create validation schemas, and the possibility to infer the Typescript type from it.

import { z } from "zod";

// Create login schema with email and password
const LoginSchema = z.object({
‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎email: z.string().email(),
‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎password: z.string().min(8),
});

// Infer output TypeScript type of login schema
type LoginData = z.infer<typeof LoginSchema>;

This makes it easy to discover available validation functions as you chain them, which is nice. However, this also leads to a larger bundle-size as you need to import the complete validation library, even if you only want to validate a string.

Valibot

Valibot has a different approach, where you have to import each validation function seperately.

// Look at the imports
import { email, minLength, object, Output, string } from "valibot";

// Create login schema with email and password
const LoginSchema = object({
‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎email: string([email()]),
‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎password: string([minLength(8)]),
});

// Infer output TypeScript type of login schema
type LoginData = Output<typeof LoginSchema>;

This makes it more difficult to discover what kind of validation is available for each type. In exchange, you only import the validation function you actually need, thus a smaller bundle-size.

The challenger: ArkType

ArkType has a different approach from these two. They use strings as the validation "functions". The strings are "just" what you otherwise would type as Typescript types. They parse the string, and gives you the correct validation function based on that.

import { type } from "arktype";

// Definitions are statically parsed and inferred as TS.
const LoginSchema = type({
‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎email: "email",
‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎password: "string>8",
});

type LoginData = typeof LoginSchema.infer;

I think this is an incredibly cool way to do it, and i would love to use it more! The syntax is cleaner (IMO), and you don't need to remember anything other than Typescript.

Conclusion

I don't think we have even scratched the surface of what's going to be possible, performance-wise or type-wise, with validation libraries. All of them has their pros and cons, and you need to consider different factors to know what's best for you use-case. DX, bundle-size, familiarity, etc...