TypeSchema
Universal adapter for TypeScript schema validation.
README
TypeSchema
Universal adapter for schema validation
Setup • API • Coverage • GitHub • npm • Deno
Many libraries rely on some sort of type validation. Their maintainers have the choice of either to:
1. Implement their own validation logic: which leads to more code to maintain, and we already have many good solutions out there (e.g. [zod](https://zod.dev), [arktype](https://arktype.io), [typia](https://typia.io))
1. Couple their code with a specific validation library: which limits adoption by developers who use another
1. Support multiple validation libraries: which is a burden to keep up-to-date (e.g. tRPC)
There's no best validation library because there's always a tradeoff. Each developer chooses the library that makes the most sense to them. TypeSchema solves this problem by easily providing option 3: support multiple validation libraries out-of-the-box.
Features
- 🚀 Decouple from schema validation libraries
- 🍃 Tiny client footprint, tree-shakeable
- 🛋️ Easy-to-use, minimal API
Usage
- ```ts
- import type {Infer, InferIn, Schema} from '@decs/typeschema';
- import {assert, validate, wrap} from '@decs/typeschema';
- // Use your favorite validation library, e.g. `zod`, `arktype`, `typia`
- const schema: Schema = z.string();
- const schema: Schema = type('string');
- const schema: Schema = typia.createAssert<string>();
- // Extracts the schema type
- type Output = Infer<typeof schema>; // `string`
- type Input = InferIn<typeof schema>; // `string`
- // Returns the wrapped schema with access to all its operations
- const wrapped = wrap(schema);
- await wrapped.validate('123'); // {success: true, data: '123'}
- await wrapped.assert('123'); // '123'
- // Returns the validated data or a list of `ValidationIssue`s
- await validate(schema, '123'); // {success: true, data: '123'}
- await validate(schema, 123); // {success: false, issues: [`ValidationIssue`]}
- // Returns the validated data or throws an `AggregateError`
- await assert(schema, '123'); // '123'
- await assert(schema, 123); // throws `AggregateError`
- ```
tRPC
You can use any supported schema on tRPC through thewrap function:
- ```ts
- import {wrap} from '@decs/typeschema';
- import {initTRPC} from '@trpc/server';
- import {object, string} from 'valibot';
- // Use your favorite validation library, e.g. `valibot`
- const schema = object({name: string()});
- const t = initTRPC.create();
- const appRouter = t.router({
- hello: t.procedure
- .input(wrap(schema)) // like this
- .query(({input}) => `Hello, ${input.name}!`),
- });
- ```
Coverage
TypeSchema supports all major schema validation libraries:
`assert` | `Infer` | `InferIn` | Example schema |
|:---------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------:|:-----------------------:|:-------:|:---------:|:------------------------------|
| [zod](https://zod.dev) | | ✅ | ✅ | ✅ | ✅ | `z.string()` || [yup](https://github.com/jquense/yup) | | ✅ | ✅ | ✅ | ✅ | `string()` || [joi](https://joi.dev) | | ✅ | ✅ | ❌ | ❌ | `Joi.string()` || [ajv](https://ajv.js.org) | | ✅ | ✅ | ❌ | ❌ | `{type: "string"}` || [superstruct](https://docs.superstructjs.org) | | ✅ | ✅ | ✅ | ❌ | `string()` || [io-ts](https://gcanti.github.io/io-ts) | | ✅ | ✅ | ✅ | ✅ | `t.string` || [ow](https://sindresorhus.com/ow)[^1] | | ✅ | ✅ | ✅ | ✅ | `ow.string` || [typia](https://typia.io) | | ✅ | ✅ | ✅ | ✅ | `typia.createAssert[^1]: For ow, only v0.28.2 is supported (sindresorhus/ow#248)
Custom validations are also supported:
- ```ts
- export function assertString(data: unknown): string {
- if (typeof data !== 'string') {
- throw new Error('Expected a string, got: ' + data);
- }
- return data;
- }
- await validate(assertString, '123'); // {success: true, data: '123'}
- await validate(assertString, 123); // {success: false, issues: [`ValidationIssue`]}
- await assert(assertString, '123'); // '123'
- await assert(assertString, 123); // throws `AggregateError`
- ```
Setup
Install TypeSchema with your package manager of choice:
npm | npm install @decs/typeschema |
---|---|
Yarn | yarn add @decs/typeschema |
pnpm | pnpm add @decs/typeschema |
Deno | https://deno.land/x/typeschema |
Vite
If using Vite, you'll also need to update yourvite.config.ts file:
- ```ts
- import {typeschemaPlugin} from '@decs/typeschema/vite';
- export default defineConfig({
- plugins: [
- typeschemaPlugin(), // add this plugin
- ],
- });
- ```
API
Types
- Schema
An union of the schema types of all supported libraries
Interface for a wrapped schema, exposing all its operations
Extracts the output type of a schema
Extracts the input type of a schema
- ValidationIssue
Includes a `message` and an optional `path`
Functions
- wrap(schema)
ts
wrap schema: TSchema,
): TypeSchema Returns the wrapped schema with access to all its operations
- validate(schema, data)
ts
validate schema: TSchema,
data: unknown,
): Promise Returns the validated data or a list of ValidationIssues
- assert(schema, data)
ts
assert schema: TSchema,
data: unknown,
): Promise Returns the validated data or throws an AggregateError
Acknowledgements
- Inspired by tRPC's input & output validators
- Adapter architecture inspired by @ecyrbe's suggestions
- API definition inspired by @colinhacks's proposal
- Logo designed by flaticon