Efficient validators from Typescript types generated by a blazing fast compiler.
- Typescript Efficient: Unlike zod, io-ts and similar, beff doesn't generate any extra work for the typescript compiler. Get a fast editor and fast compile times.
- Fast: Beff is written in Rust and compiled to WASM. It is supported by every OS and should work for you!
- Really fast: Beff compiles a hello-world project in 5ms. A big project with +200 types is compiled in 200ms.
- Compatible: Beff uses the Typescript compiler for path resolution. If your editor can find the types, so can beff.
- Efficient generated code: Beff generates optimal validator code, applying many optimizations to it at compile time.
- Helpful: Beff generates clear error messages at compile time and at validation time.
- Powerful: Beff supports recursive types, generic types, mapped types, conditional types,
Omit
,Exclude
,Partial
,Required
,Record
and a lot more. If it makes sense to have a runtime validator for that type, beff will understand it.
Install @beff/cli
and @beff/client
from npm.
npm i @beff/cli @beff/client
Create a json file to configure beff. The file can have any name, but it's standard practice to name if beff.json
.
{
"parser": "./src/parser.ts",
"outputDir": "./src/generated"
}
Create a typescript file that lists the types for which beff should generate validator for.
It's standard practice to call it parser.ts
import parse from "./generated/parser";
type User = {
name: string;
age: number;
};
export const Parsers = parse.buildParsers<{
User: User;
}>();
@beff/cli
installs a beff
binary.
npx beff -p beff.json
import { Parsers } from "./parser.ts";
const user1 = Parsers.User.parse({
name: "John Doe",
age: 42,
});
const maybeUser = Parser.User.safeParse(null);
The beff
binary can run in watch mode, too.
$ npx beff -h
Usage: beff [options]
Generate validators from typescript types
Options:
-p, --project <string> Path to the project file
-v, --verbose Print verbose output
-w, --watch Watch for file changes
-h, --help display help for command
Generate flat JSON schema from types.
Recursive types are not supported and become the equivalent of any
in the second time they appear.
Configure your beff.json
{
"parser": "./src/parser.ts",
"outputDir": "./src/generated"
}
Import the generated code and configure types that will be exported.
import s from "./generated/schema";
type ProfileData = {
name: string;
};
type User = {
profile: ProfileData;
age: number;
};
export const Schemas = s.buildSchemas<{
User: User;
}>();
console.log(Schemas.User); // JSON Schema without references
Configure your beff.json
{
"parser": "./src/parser.ts",
"outputDir": "./src/generated",
"customFormats": [
{
"name": "ValidCurrency"
}
]
}
Use the helper StringFormat
to create the type. It creates a branded typescript type.
Define the runtime validator in the build parsers call.
import parse from "./generated/parser";
import { StringFormat } from "@beff/cli";
export type ValidCurrency = StringFormat<"ValidCurrency">;
export const Parsers = parse.buildParsers<{
ValidCurrency: ValidCurrency;
}>({
customFormats: {
ValidCurrency: (input: string) => {
if (VALID_CURRENCIES.include(input)) {
return true;
}
return false;
},
},
});
Beff supports a type creation API similar to zod
, io-ts
and similar.
However, Beff's type creation API is very limited and only supports a few types.
With Beff, complex types should be generated by compiling Typescript types.
Types generated with the ad-hoc API have the same properties and methods as regular compiled types.
import { b } from "@beff/client";
const AdHocItem = b.Object({
str: b.String(),
num: b.Number(),
bool: b.Boolean(),
undefined: b.Undefined(),
null: b.Null(),
any: b.Any(),
unknown: b.Unknown(),
});
const AdHocList = b.Array(AdHocItem);
const ls = AdHocList.parse([]);
Call .zod()
on a parser to create a zod
type.
Useful for gradually migrating from zod
.
import { Parsers } from "./parser.ts";
import { z } from "zod";
const users = z.array(Parsers.User.zod()).parse({
name: "John Doe",
age: 42,
});
Please read CONTRIBUTING.md