Efficient validators from Typescript types generated by a blazing fast compiler
Efficient validators from Typescript types generated by a blazing fast compiler.
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