jtd-ts

jtd-ts is a typescript first jtd parser, validator, and fuzzer

The root of the API is exposed through a CompiledSchema, which represents a compiled JTD schema and has methods for guarding if an object complies, fuzzing random objects, or getting the underlying schema.

There are two primary ways to compile a schema, using native typescript functions, or compiling a raw schema.

Native Typescript Functions

The first is the typescript native way, using functions that have similar names to their JTD counterparts, e.g. boolean. The advantage of this aproach is that it's a little less verbose, and it skips some checks compared to compiling a raw schema. The disadvantage is that there are some concncepts in JTD that this can not express, primarily, circular refs. This interface doesn't allow declaring an infinite type.

Every function except for compile corresponds to its appropriate schema definition. In addition, there are three functions that behave slightly differently.

  1. nullable - modifies an existing schema to make it nullable
  2. metadata - modifies an existing schema to include metadata, the type of the metadata is preserved.
  3. definitions - creates a builder to accurately type a directed acyclic graph of definitions and references, before needing to call build to create the actual CompiledSchema.

Usage

import { boolean, properties, float64 } from "jtd-ts";

const schema = properties({ bool: boolean() }, { optFloat: float64() });

// guard against unknown objects with `.guard()`
const obj: unknown = // ...
if (schema.guard(obj)) {
obj satisfies { bool: boolean; optFloat?: number };
}

// create random data that complies with schema with `.fuzz()`
const fuzzed: { bool: boolean; optFloat?: number } = schema.fuzz();

// get a fully typed output schema with `.schema()`
const export: {
properties: { bool: { type: "boolean" } };
optionalProperties: { optFloat: { type: "float64" } };
} = schema.schema();

Schema Compilation

If you've defined your schema elsewhere, you can similarly just compile it in typescript. The advantage of this is portability, and typescript will infer the appropriate type for the guards. It can also handle circular refs. The downside is it's more verbose, and the type checking doesn't regonize all errors, so if you're not targeting portability, the other interface is better, and can still export the corresponding schema.

In addition to the compile function, this API also exposes interfaces for the various schemas, like BooleanSchema.

Usage

import { compile } from "jtd-ts";

const schema = compile({
properties: { bool: { type: "boolean" } },
optionalProperties: { optFloat: { type: "float64" } },
});

// guard against unknown objects with `.guard()`
const obj: unknown = // ...
if (schema.guard(obj)) {
obj satisfies { bool: boolean; optFloat?: number };
}

// create random data that complies with schema with `.fuzz()`
const fuzzed: { bool: boolean; optFloat?: number } = schema.fuzz();

Index

Interfaces

Type Aliases

Functions