Big update!Introducing GitHub Bot Commands. Learn more
Socket
Log inBook a demo

@sinclair/typebox

Package Overview
Dependencies
0
Maintainers
1
Versions
138
Issues
File Explorer

Advanced tools

@sinclair/typebox

JSONSchema Type Builder with Static Type Resolution for TypeScript

    0.25.10latest

Version published
Maintainers
1
Weekly downloads
9,124,049
decreased by-9.38%

Weekly downloads

Changelog

Source

0.25.10

Updates:

  • 283 Updates the custom type validator callback signature to accept a schema instance. The schema instance may include additional constraints (such as options) that may be used during the validation process. Custom.Set('<Kind>', (schema, value) => { ... }).

Readme

Source

TypeBox

JSON Schema Type Builder with Static Type Resolution for TypeScript



npm version Downloads GitHub CI

Install

npm

$ npm install @sinclair/typebox --save

deno

import { Static, Type } from 'npm:@sinclair/typebox'

esm

import { Static, Type } from 'https://esm.sh/@sinclair/typebox'

Usage

import { Static, Type } from '@sinclair/typebox' const T = Type.Object({ // const T = { x: Type.Number(), // type: 'object', y: Type.Number(), // required: ['x', 'y', 'z'], z: Type.Number() // properties: { }) // x: { type: 'number' }, // y: { type: 'number' }, // z: { type: 'number' } // } // } type T = Static<typeof T> // type T = { // x: number, // y: number, // z: number // }

Overview

TypeBox is a type builder library that creates in-memory JSON Schema objects that can be statically inferred as TypeScript types. The schemas produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox enables one to create a unified type that can be statically checked by TypeScript and runtime asserted using standard JSON Schema validation.

TypeBox is designed to enable JSON schema to compose with the same flexibility as TypeScript's type system. It can be used either as a simple tool to build up complex schemas or integrated into REST and RPC services to help validate data received over the wire.

License MIT

Contents

Example

The following demonstrates TypeBox's general usage.

import { Static, Type } from '@sinclair/typebox' //-------------------------------------------------------------------------------------------- // // Let's say you have the following type ... // //-------------------------------------------------------------------------------------------- type T = { id: string, name: string, timestamp: number } //-------------------------------------------------------------------------------------------- // // ... you can express this type in the following way. // //-------------------------------------------------------------------------------------------- const T = Type.Object({ // const T = { id: Type.String(), // type: 'object', name: Type.String(), // properties: { timestamp: Type.Integer() // id: { }) // type: 'string' // }, // name: { // type: 'string' // }, // timestamp: { // type: 'integer' // } // }, // required: [ // 'id', // 'name', // 'timestamp' // ] // } //-------------------------------------------------------------------------------------------- // // ... then infer back to the original static type this way. // //-------------------------------------------------------------------------------------------- type T = Static<typeof T> // type T = { // id: string, // name: string, // timestamp: number // } //-------------------------------------------------------------------------------------------- // // ... then use the type both as JSON schema and as a TypeScript type. // //-------------------------------------------------------------------------------------------- function receive(value: T) { // ... as a Type if(JSON.validate(T, value)) { // ... as a Schema // ok... } }

Types

TypeBox provides a set of functions that allow you to compose JSON Schema similar to how you would compose static types with TypeScript. Each function creates a JSON schema fragment which can compose into more complex types. The schemas produced by TypeBox can be passed directly to any JSON Schema compliant validator, or used to reflect runtime metadata for a type.

Standard Types

The following table lists the Standard TypeBox types.

┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐ │ TypeBox │ TypeScript │ JSON Schema │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Any() │ type T = anyconst T = { } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Unknown() │ type T = unknown │ const T = { } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.String() │ type T = stringconst T = { │ │ │ │ type: 'string' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Number() │ type T = numberconst T = { │ │ │ │ type: 'number' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Integer() │ type T = numberconst T = { │ │ │ │ type: 'integer' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Boolean() │ type T = booleanconst T = { │ │ │ │ type: 'boolean' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Null() │ type T = nullconst T = { │ │ │ │ type: 'null' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.RegEx(/foo/) │ type T = stringconst T = { │ │ │ │ type: 'string', │ │ │ │ pattern: 'foo' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Literal(42) │ type T = 42const T = { │ │ │ │ const: 42, │ │ │ │ type: 'number' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Array( │ type T = number[] │ const T = { │ │ Type.Number() │ │ type: 'array', │ │ ) │ │ items: { │ │ │ │ type: 'number' │ │ │ │ } │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Object({ │ type T = { │ const T = { │ │ x: Type.Number(), │ x: number, │ type: 'object', │ │ y: Type.Number() │ y: number │ properties: { │ │ }) │ } │ x: { │ │ │ │ type: 'number' │ │ │ │ }, │ │ │ │ y: { │ │ │ │ type: 'number' │ │ │ │ } │ │ │ │ }, │ │ │ │ required: ['x', 'y'] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │ │ Type.Number(), │ │ type: 'array', │ │ Type.Number() │ │ items: [{ │ │ ]) │ │ type: 'number' │ │ │ │ }, { │ │ │ │ type: 'number' │ │ │ │ }], │ │ │ │ additionalItems: false, │ │ │ │ minItems: 2, │ │ │ │ maxItems: 2 │ │ │ │ } │ │ │ │ │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ enum Foo { │ enum Foo { │ const T = { │ │ A, │ A, │ anyOf: [{ │ │ B │ B │ type: 'number', │ │ } │ } │ const: 0 │ │ │ │ }, { │ │ const T = Type.Enum(Foo) │ type T = Foo │ type: 'number', │ │ │ │ const: 1 │ │ │ │ }] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.KeyOf( │ type T = keyof { │ const T = { │ │ Type.Object({ │ x: number, │ anyOf: [{ │ │ x: Type.Number(), │ y: numbertype: 'string', │ │ y: Type.Number() │ } │ const: 'x' │ │ }) │ │ }, { │ │ ) │ │ type: 'string', │ │ │ │ const: 'y' │ │ │ │ }] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Union([ │ type T = string | numberconst T = { │ │ Type.String(), │ │ anyOf: [{ │ │ Type.Number() │ │ type: 'string' │ │ ]) │ │ }, { │ │ │ │ type: 'number' │ │ │ │ }] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Intersect([ │ type T = { │ const T = { │ │ Type.Object({ │ x: numbertype: 'object', │ │ x: Type.Number() │ } & { │ properties: { │ │ }), │ y: number │ x: { │ │ Type.Object({ │ } │ type: 'number' │ │ y: Type.Number() │ │ }, │ │ }) │ │ y: { │ │ ]) │ │ type: 'number' │ │ │ │ } │ │ │ │ }, │ │ │ │ required: ['x', 'y'] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Never() │ type T = neverconst T = { │ │ │ │ allOf: [{ │ │ │ │ type: 'boolean', │ │ │ │ const: false │ │ │ │ }, { │ │ │ │ type: 'boolean', │ │ │ │ const: true │ │ │ │ }] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Record( │ type T = Record< │ const T = { │ │ Type.String(), │ string, │ type: 'object', │ │ Type.Number() │ number, │ patternProperties: { │ │ ) │ > │ '^.*$': { │ │ │ │ type: 'number' │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Partial( │ type T = Partial<{ │ const T = { │ │ Type.Object({ │ x: number, │ type: 'object', │ │ x: Type.Number(), │ y: number │ properties: { │ │ y: Type.Number() | }> │ x: { │ │ }) │ │ type: 'number' │ │ ) │ │ }, │ │ │ │ y: { │ │ │ │ type: 'number' │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Required( │ type T = Required<{ │ const T = { │ │ Type.Object({ │ x?: number, │ type: 'object', │ │ x: Type.Optional( │ y?: number │ properties: { │ │ Type.Number() | }> │ x: { │ │ ), │ │ type: 'number' │ │ y: Type.Optional( │ │ }, │ │ Type.Number() │ │ y: { │ │ ) │ │ type: 'number' │ │ }) │ │ } │ │ ) │ │ }, │ │ │ │ required: ['x', 'y'] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Pick( │ type T = Pick<{ │ const T = { │ │ Type.Object({ │ x: number, │ type: 'object', │ │ x: Type.Number(), │ y: number │ properties: { │ │ y: Type.Number() | }, 'x'> │ x: { │ │ }), ['x'] │ │ type: 'number' │ │ ) │ │ } │ │ │ │ }, │ │ │ │ required: ['x'] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Omit( │ type T = Omit<{ │ const T = { │ │ Type.Object({ │ x: number, │ type: 'object', │ │ x: Type.Number(), │ y: number │ properties: { │ │ y: Type.Number() | }, 'x'> │ y: { │ │ }), ['x'] │ │ type: 'number' │ │ ) │ │ } │ │ │ │ }, │ │ │ │ required: ['y'] │ │ │ │ } │ │ │ │ │ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘

Extended Types

TypeBox provides a set of extended types that can be used to express schematics for core JavaScript constructs and primitives. Extended types are not valid JSON Schema and will not validate using typical validation. These types however can be used to frame JSON schema and describe callable RPC interfaces that may receive JSON validated data.

┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐ │ TypeBox │ TypeScript │ Extended Schema │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Constructor([ │ type T = new ( │ const T = { │ │ Type.String(), │ arg0: string, │ type: 'object', │ │ Type.Number() │ arg1: number │ instanceOf: 'Constructor', │ │ ], Type.Boolean()) │ ) => boolean │ parameters: [{ │ │ │ │ type: 'string' │ │ │ │ }, { │ │ │ │ type: 'number' │ │ │ │ }], │ │ │ │ return: { │ │ │ │ type: 'boolean' │ │ │ │ } │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Function([ │ type T = ( │ const T = { │ | Type.String(), │ arg0: string, │ type : 'object', │ │ Type.Number() │ arg1: number │ instanceOf: 'Function', │ │ ], Type.Boolean()) │ ) => boolean │ parameters: [{ │ │ │ │ type: 'string' │ │ │ │ }, { │ │ │ │ type: 'number' │ │ │ │ }], │ │ │ │ return: { │ │ │ │ type: 'boolean' │ │ │ │ } │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Promise( │ type T = Promise<string> │ const T = { │ │ Type.String() │ │ type: 'object', │ │ ) │ │ instanceOf: 'Promise', │ │ │ │ item: { │ │ │ │ type: 'string' │ │ │ │ } │ │ │ │ } │ │ │ │ │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Uint8Array() │ type T = Uint8Arrayconst T = { │ │ │ │ type: 'object', │ │ │ │ instanceOf: 'Uint8Array' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Date() │ type T = Dateconst T = { │ │ │ │ type: 'object', │ │ │ │ instanceOf: 'Date' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Undefined() │ type T = undefinedconst T = { │ │ │ │ type: 'null', │ │ │ │ typeOf: 'Undefined' │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Void() │ type T = voidconst T = { │ │ │ │ type: 'null' │ │ │ │ typeOf: 'Void' │ │ │ │ } │ │ │ │ │ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘

Modifiers

TypeBox provides modifiers that can be applied to an objects properties. This allows for optional and readonly to be applied to that property. The following table illustates how they map between TypeScript and JSON Schema.

┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐ │ TypeBox │ TypeScript │ JSON Schema │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Object({ │ type T = { │ const T = { │ │ name: Type.Optional( │ name?: string │ type: 'object', │ │ Type.String() │ } │ properties: { │ │ ) │ │ name: { │ │ }) │ │ type: 'string' │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Object({ │ type T = { │ const T = { │ │ name: Type.Readonly( │ readonly name: string │ type: 'object', │ │ Type.String() │ } │ properties: { │ │ ) │ │ name: { │ │ }) │ │ type: 'string' │ │ │ │ } │ │ │ │ }, │ │ │ │ required: ['name'] │ │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Type.Object({ │ type T = { │ const T = { │ │ name: Type.ReadonlyOptional( │ readonly name?: string │ type: 'object', │ │ Type.String() │ } │ properties: { │ │ ) │ │ name: { │ │ }) │ │ type: 'string' │ │ │ │ } │ │ │ │ } │ │ │ │ } │ │ │ │ │ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘

Options

You can pass additional JSON schema options on the last argument of any given type. The following are some examples.

// string must be an email const T = Type.String({ format: 'email' }) // number must be a multiple of 2 const T = Type.Number({ multipleOf: 2 }) // array must have at least 5 integer values const T = Type.Array(Type.Integer(), { minItems: 5 })

Reference

Use Type.Ref(...) to create referenced types. The target type must specify an $id.

const T = Type.String({ $id: 'T' }) // const T = { // $id: 'T', // type: 'string' // } const R = Type.Ref(T) // const R = { // $ref: 'T' // }

Recursive

Use Type.Recursive(...) to create recursive types.

const Node = Type.Recursive(Node => Type.Object({ // const Node = { id: Type.String(), // $id: 'Node', nodes: Type.Array(Node) // type: 'object', }), { $id: 'Node' }) // properties: { // id: { // type: 'string' // }, // nodes: { // type: 'array', // items: { // $ref: 'Node' // } // } // }, // required: [ // 'id', // 'nodes' // ] // } type Node = Static<typeof Node> // type Node = { // id: string // nodes: Node[] // } function test(node: Node) { const id = node.nodes[0].nodes[0] // id is string .nodes[0].nodes[0] .id }

Generic

Use functions to create generic types. The following creates a generic Nullable<T> type.

import { Type, Static, TSchema } from '@sinclair/typebox' const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()]) const T = Nullable(Type.String()) // const T = { // anyOf: [{ // type: 'string' // }, { // type: 'null' // }] // } type T = Static<typeof T> // type T = string | null const U = Nullable(Type.Number()) // const U = { // anyOf: [{ // type: 'number' // }, { // type: 'null' // }] // } type U = Static<typeof U> // type U = number | null

Conditional

Use the conditional module to create Conditional Types. This module implements TypeScript's structural equivalence checks to enable TypeBox types to be conditionally inferred at runtime. This module also provides the Extract and Exclude utility types which are expressed as conditional types in TypeScript.

The conditional module is provided as an optional import.

import { Conditional } from '@sinclair/typebox/conditional'

The following table shows the TypeBox mappings between TypeScript and JSON schema.

┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐ │ TypeBox │ TypeScript │ JSON Schema │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Conditional.Extends( │ type T = │ const T = { │ │ Type.String(), │ string extends number │ const: false, │ │ Type.Number(), │ true : false │ type: 'boolean' │ │ Type.Literal(true), │ │ } │ │ Type.Literal(false) │ │ │ │ ) │ │ │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Conditional.Extract( │ type T = Extract< │ const T = { │ │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │ │ Type.Literal('a'), │ 'a' | 'f' │ const: 'a' │ │ Type.Literal('b'), │ > │ type: 'string' │ │ Type.Literal('c') │ │ }] │ │ ]), │ │ } │ │ Type.Union([ │ │ │ │ Type.Literal('a'), │ │ │ │ Type.Literal('f') │ │ │ │ ]) │ │ │ │ ) │ │ │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ │ const T = Conditional.Exclude( │ type T = Exclude< │ const T = { │ │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │ │ Type.Literal('a'), │ 'a' │ const: 'b', │ │ Type.Literal('b'), │ > │ type: 'string' │ │ Type.Literal('c') │ │ }, { │ │ ]), │ │ const: 'c', │ │ Type.Union([ │ │ type: 'string' │ │ Type.Literal('a') │ │ }] │ │ ]) │ │ } │ │ ) │ │ │ │ │ │ │ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘

Unsafe

Use Type.Unsafe(...) to create custom schemas with user defined inference rules.

const T = Type.Unsafe<string>({ type: 'number' }) // const T = { // type: 'number' // } type T = Static<typeof T> // type T = string

This function can be used to create custom schemas for validators that require specific schema representations. An example of this might be OpenAPI's nullable and enum schemas which are not provided by TypeBox. The following demonstrates using Type.Unsafe(...) to create these types.

import { Type, Static, TSchema } from '@sinclair/typebox' //-------------------------------------------------------------------------------------------- // // Nullable<T> // //-------------------------------------------------------------------------------------------- function Nullable<T extends TSchema>(schema: T) { return Type.Unsafe<Static<T> | null>({ ...schema, nullable: true }) } const T = Nullable(Type.String()) // const T = { // type: 'string', // nullable: true // } type T = Static<typeof T> // type T = string | null //-------------------------------------------------------------------------------------------- // // StringEnum<string[]> // //-------------------------------------------------------------------------------------------- function StringEnum<T extends string[]>(values: [...T]) { return Type.Unsafe<T[number]>({ type: 'string', enum: values }) } const T = StringEnum(['A', 'B', 'C']) // const T = { // enum: ['A', 'B', 'C'] // } type T = Static<typeof T> // type T = 'A' | 'B' | 'C'

Guards

Use the guard module to test if values are TypeBox types.

import { TypeGuard } from '@sinclair/typebox/guard' const T = Type.String() if(TypeGuard.TString(T)) { // T is TString }

Strict

TypeBox schemas contain the Kind and Modifier symbol properties. These properties are provided to enable runtime type reflection on schemas, as well as helping TypeBox internally compose types. These properties are not strictly valid JSON schema; so in some cases it may be desirable to omit them. TypeBox provides a Type.Strict() function that will omit these properties if necessary.

const T = Type.Object({ // const T = { name: Type.Optional(Type.String()) // [Kind]: 'Object', }) // type: 'object', // properties: { // name: { // [Kind]: 'String', // type: 'string', // [Modifier]: 'Optional' // } // } // } const U = Type.Strict(T) // const U = { // type: 'object', // properties: { // name: { // type: 'string' // } // } // }

Values

TypeBox includes an optional values module that can be used to perform common operations on JavaScript values. This module enables one to create, check and cast values from types. It also provides functionality to check equality, clone and diff and patch JavaScript values. The value module is provided as an optional import.

import { Value } from '@sinclair/typebox/value'

Create

Use the Create function to create a value from a TypeBox type. TypeBox will use default values if specified.

const T = Type.Object({ x: Type.Number(), y: Type.Number({ default: 42 }) }) const A = Value.Create(T) // const A = { x: 0, y: 42 }

Clone

Use the Clone function to deeply clone a value

const A = Value.Clone({ x: 1, y: 2, z: 3 }) // const A = { x: 1, y: 2, z: 3 }

Check

Use the Check function to type check a value

const T = Type.Object({ x: Type.Number() }) const R = Value.Check(T, { x: 1 }) // const R = true

Cast

Use the Cast function to cast a value into a type. The cast function will retain as much information as possible from the original value.

const T = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false }) const X = Value.Cast(T, null) // const X = { x: 0, y: 0 } const Y = Value.Cast(T, { x: 1 }) // const Y = { x: 1, y: 0 } const Z = Value.Cast(T, { x: 1, y: 2, z: 3 }) // const Z = { x: 1, y: 2 }

Equal

Use the Equal function to deeply check for value equality.

const R = Value.Equal( // const R = true { x: 1, y: 2, z: 3 }, { x: 1, y: 2, z: 3 } )

Diff

Use the Diff function to produce a sequence of edits to transform one value into another.

const E = Value.Diff( // const E = [ { x: 1, y: 2, z: 3 }, // { type: 'update', path: '/y', value: 4 }, { y: 4, z: 5, w: 6 } // { type: 'update', path: '/z', value: 5 }, ) // { type: 'insert', path: '/w', value: 6 }, // { type: 'delete', path: '/x' } // ]

Patch

Use the Patch function to apply edits

const A = { x: 1, y: 2 } const B = { x: 3 } const E = Value.Diff(A, B) // const E = [ // { type: 'update', path: '/x', value: 3 }, // { type: 'delete', path: '/y' } // ] const C = Value.Patch<typeof B>(A, E) // const C = { x: 3 }

Errors

Use the Errors function enumerate validation errors.

const T = Type.Object({ x: Type.Number(), y: Type.Number() }) const R = [...Value.Errors(T, { x: '42' })] // const R = [{ // schema: { type: 'number' }, // path: '/x', // value: '42', // message: 'Expected number' // }, { // schema: { type: 'number' }, // path: '/y', // value: undefined, // message: 'Expected number' // }]

Pointer

Use ValuePointer to perform mutable updates on existing values using RFC6901 Json Pointers.

import { ValuePointer } from '@sinclair/typebox/value' const A = { x: 0, y: 0, z: 0 } ValuePointer.Set(A, '/x', 1) // const A = { x: 1, y: 0, z: 0 } ValuePointer.Set(A, '/y', 1) // const A = { x: 1, y: 1, z: 0 } ValuePointer.Set(A, '/z', 1) // const A = { x: 1, y: 1, z: 1 }

TypeCheck

TypeBox targets JSON Schema Draft 6 and is built and tested against the Ajv JSON Schema validator for standards compliance. TypeBox also includes an optional built-in TypeCompiler that can provide improved compilation and validation performance specifically for TypeBox types only.

The following sections detail using these validators.

Ajv

The following are the recommended configurations to support both the Standard and Extended type sets provided by TypeBox. For schema portability and publishing to remote systems, it is recommended to use the Standard type set only.

$ npm install ajv ajv-formats --save
Standard Ajv Configuration

Expand for Standard Type Set Configuration

import { Type } from '@sinclair/typebox' import addFormats from 'ajv-formats' import Ajv from 'ajv' export function createAjv() { return addFormats(new Ajv({}), [ 'date-time', 'time', 'date', 'email', 'hostname', 'ipv4', 'ipv6', 'uri', 'uri-reference', 'uuid', 'uri-template', 'json-pointer', 'relative-json-pointer', 'regex' ]) } const ajv = createAjv() const R = ajv.validate(Type.Object({ // const R = true x: Type.Number(), y: Type.Number(), z: Type.Number() }), { x: 1, y: 2, z: 3 })
Extended Ajv Configuration

Expand for Extended Type Set Configuration

import { TypeGuard } from '@sinclair/typebox/guard' import { Value } from '@sinclair/typebox/value' import { Type } from '@sinclair/typebox' import addFormats from 'ajv-formats' import Ajv from 'ajv' function schemaOf(schemaOf: string, value: unknown, schema: unknown) { switch (schemaOf) { case 'Constructor': return TypeGuard.TConstructor(schema) && Value.Check(schema, value) // not supported case 'Function': return TypeGuard.TFunction(schema) && Value.Check(schema, value) // not supported case 'Date': return TypeGuard.TDate(schema) && Value.Check(schema, value) case 'Promise': return TypeGuard.TPromise(schema) && Value.Check(schema, value) // not supported case 'Uint8Array': return TypeGuard.TUint8Array(schema) && Value.Check(schema, value) case 'Undefined': return TypeGuard.TUndefined(schema) && Value.Check(schema, value) // not supported case 'Void': return TypeGuard.TVoid(schema) && Value.Check(schema, value) default: return false } } export function createAjv() { return addFormats(new Ajv({}), [ 'date-time', 'time', 'date', 'email', 'hostname', 'ipv4', 'ipv6', 'uri', 'uri-reference', 'uuid', 'uri-template', 'json-pointer', 'relative-json-pointer', 'regex' ]) .addKeyword({ type: 'object', keyword: 'instanceOf', validate: schemaOf }) .addKeyword({ type: 'null', keyword: 'typeOf', validate: schemaOf }) .addKeyword('exclusiveMinimumTimestamp') .addKeyword('exclusiveMaximumTimestamp') .addKeyword('minimumTimestamp') .addKeyword('maximumTimestamp') .addKeyword('minByteLength') .addKeyword('maxByteLength') } const ajv = createAjv() const R = ajv.validate(Type.Object({ // const R = true buffer: Type.Uint8Array(), date: Type.Date(), void: Type.Void() }), { buffer: new Uint8Array(), date: new Date(), void: null })

TypeCompiler

TypeBox provides an optional high performance just-in-time (JIT) compiler and type checker that can be used in applications that require extremely fast validation. Note that this compiler is optimized for TypeBox types only where the schematics are known in advance. If defining custom types with Type.Unsafe<T> please consider Ajv.

The compiler module is provided as an optional import.

import { TypeCompiler } from '@sinclair/typebox/compiler'

Use the Compile(...) function to compile a type.

const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{ x: Type.Number(), // x: TNumber; y: Type.Number(), // y: TNumber; z: Type.Number() // z: TNumber; })) // }>> const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true

Validation errors can be read with the Errors(...) function.

const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{ x: Type.Number(), // x: TNumber; y: Type.Number(), // y: TNumber; z: Type.Number() // z: TNumber; })) // }>> const value = { } const errors = [...C.Errors(value)] // const errors = [{ // schema: { type: 'number' }, // path: '/x', // value: undefined, // message: 'Expected number' // }, { // schema: { type: 'number' }, // path: '/y', // value: undefined, // message: 'Expected number' // }, { // schema: { type: 'number' }, // path: '/z', // value: undefined, // message: 'Expected number' // }]

Compiled routines can be inspected with the .Code() function.

const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString> console.log(C.Code()) // return function check(value) { // return ( // (typeof value === 'string') // ) // }

Custom Types

Use the custom module to create user defined types. User defined types require a [Kind] symbol property which is used to match the schema against a registered type. Custom types are specific to TypeBox and can only be used with the TypeCompiler and Value modules.

The custom module is an optional import.

import { Custom } from '@sinclair/typebox/custom'

The following creates a BigInt type.

import { Type, Kind } from '@sinclair/typebox' Custom.Set('BigInt', (schema, value) => typeof value === 'bigint') // │ // └────────────────────────────┐ The [Kind] is used to match registered type // │ const T = Type.Unsafe<bigint>({ [Kind]: 'BigInt' }) // const T = { [Kind]: 'BigInt' } const A = TypeCompiler.Compile(T).Check(65536) // const A = false const B = Value.Check(T, 65536n) // const B = true

Custom Formats

Use the format module to create user defined string formats. If using Ajv, please refer to the official Ajv format documentation located here. The format module is specific to TypeBox can only be used with the TypeCompiler and Value modules.

The format module is an optional import.

import { Format } from '@sinclair/typebox/format'

The following creates a palindrome string format.

Format.Set('palindrome', value => value === value.split('').reverse().join(''))

Once set, this format can then be used by the TypeCompiler and Value modules.

const T = Type.String({ format: 'palindrome' }) const A = TypeCompiler.Compile(T).Check('engine') // const A = false const B = Value.Check(T, 'kayak') // const B = true

Benchmark

This project maintains a set of benchmarks that measure Ajv, Value and TypeCompiler compilation and validation performance. These benchmarks can be run locally by cloning this repository and running npm run benchmark. The results below show for Ajv version 8.11.2.

For additional comparative benchmarks, please refer to typescript-runtime-type-benchmarks.

Compile

This benchmark measures compilation performance for varying types. You can review this benchmark here.

┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┐ │ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │ ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┤ │ Number │ 2000 │ ' 414 ms' │ ' 14 ms' │ ' 29.57 x' │ │ String │ 2000 │ ' 326 ms' │ ' 12 ms' │ ' 27.17 x' │ │ Boolean │ 2000 │ ' 301 ms' │ ' 11 ms' │ ' 27.36 x' │ │ Null │ 2000 │ ' 253 ms' │ ' 8 ms' │ ' 31.63 x' │ │ RegEx │ 2000 │ ' 480 ms' │ ' 18 ms' │ ' 26.67 x' │ │ ObjectA │ 2000 │ ' 2704 ms' │ ' 53 ms' │ ' 51.02 x' │ │ ObjectB │ 2000 │ ' 2846 ms' │ ' 35 ms' │ ' 81.31 x' │ │ Tuple │ 2000 │ ' 1244 ms' │ ' 23 ms' │ ' 54.09 x' │ │ Union │ 2000 │ ' 1222 ms' │ ' 26 ms' │ ' 47.00 x' │ │ Vector42000 │ ' 1522 ms' │ ' 22 ms' │ ' 69.18 x' │ │ Matrix42000 │ ' 830 ms' │ ' 10 ms' │ ' 83.00 x' │ │ Literal_String │ 2000 │ ' 348 ms' │ ' 9 ms' │ ' 38.67 x' │ │ Literal_Number │ 2000 │ ' 356 ms' │ ' 9 ms' │ ' 39.56 x' │ │ Literal_Boolean │ 2000 │ ' 353 ms' │ ' 6 ms' │ ' 58.83 x' │ │ Array_Number │ 2000 │ ' 686 ms' │ ' 11 ms' │ ' 62.36 x' │ │ Array_String │ 2000 │ ' 722 ms' │ ' 11 ms' │ ' 65.64 x' │ │ Array_Boolean │ 2000 │ ' 724 ms' │ ' 9 ms' │ ' 80.44 x' │ │ Array_ObjectA │ 2000 │ ' 3706 ms' │ ' 36 ms' │ ' 102.94 x' │ │ Array_ObjectB │ 2000 │ ' 3678 ms' │ ' 38 ms' │ ' 96.79 x' │ │ Array_Tuple │ 2000 │ ' 2217 ms' │ ' 23 ms' │ ' 96.39 x' │ │ Array_Union │ 2000 │ ' 1654 ms' │ ' 24 ms' │ ' 68.92 x' │ │ Array_Vector42000 │ ' 2283 ms' │ ' 20 ms' │ ' 114.15 x' │ │ Array_Matrix42000 │ ' 1567 ms' │ ' 19 ms' │ ' 82.47 x' │ └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┘

Validate

This benchmark measures validation performance for varying types. You can review this benchmark here.

┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┬──────────────┐ │ (index) │ Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │ ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ │ Number │ 1000000 │ ' 33 ms' │ ' 6 ms' │ ' 5 ms' │ ' 1.20 x' │ │ String │ 1000000 │ ' 26 ms' │ ' 24 ms' │ ' 12 ms' │ ' 2.00 x' │ │ Boolean │ 1000000 │ ' 24 ms' │ ' 22 ms' │ ' 11 ms' │ ' 2.00 x' │ │ Null │ 1000000 │ ' 28 ms' │ ' 24 ms' │ ' 11 ms' │ ' 2.18 x' │ │ RegEx │ 1000000 │ ' 171 ms' │ ' 56 ms' │ ' 41 ms' │ ' 1.37 x' │ │ ObjectA │ 1000000 │ ' 614 ms' │ ' 42 ms' │ ' 24 ms' │ ' 1.75 x' │ │ ObjectB │ 1000000 │ ' 1109 ms' │ ' 59 ms' │ ' 45 ms' │ ' 1.31 x' │ │ Tuple │ 1000000 │ ' 122 ms' │ ' 25 ms' │ ' 13 ms' │ ' 1.92 x' │ │ Union │ 1000000 │ ' 316 ms' │ ' 26 ms' │ ' 16 ms' │ ' 1.63 x' │ │ Recursive │ 1000000 │ ' 3219 ms' │ ' 453 ms' │ ' 128 ms' │ ' 3.54 x' │ │ Vector41000000 │ ' 145 ms' │ ' 26 ms' │ ' 13 ms' │ ' 2.00 x' │ │ Matrix41000000 │ ' 537 ms' │ ' 42 ms' │ ' 28 ms' │ ' 1.50 x' │ │ Literal_String │ 1000000 │ ' 51 ms' │ ' 21 ms' │ ' 11 ms' │ ' 1.91 x' │ │ Literal_Number │ 1000000 │ ' 48 ms' │ ' 20 ms' │ ' 11 ms' │ ' 1.82 x' │ │ Literal_Boolean │ 1000000 │ ' 49 ms' │ ' 20 ms' │ ' 11 ms' │ ' 1.82 x' │ │ Array_Number │ 1000000 │ ' 438 ms' │ ' 35 ms' │ ' 19 ms' │ ' 1.84 x' │ │ Array_String │ 1000000 │ ' 468 ms' │ ' 33 ms' │ ' 23 ms' │ ' 1.43 x' │ │ Array_Boolean │ 1000000 │ ' 448 ms' │ ' 36 ms' │ ' 29 ms' │ ' 1.24 x' │ │ Array_ObjectA │ 1000000 │ ' 13904 ms' │ ' 2536 ms' │ ' 1530 ms' │ ' 1.66 x' │ │ Array_ObjectB │ 1000000 │ ' 16188 ms' │ ' 2724 ms' │ ' 1834 ms' │ ' 1.49 x' │ │ Array_Tuple │ 1000000 │ ' 1725 ms' │ ' 98 ms' │ ' 64 ms' │ ' 1.53 x' │ │ Array_Union │ 1000000 │ ' 4762 ms' │ ' 237 ms' │ ' 87 ms' │ ' 2.72 x' │ │ Array_Recursive │ 1000000 │ ' 54754 ms' │ ' 7707 ms' │ ' 1152 ms' │ ' 6.69 x' │ │ Array_Vector41000000 │ ' 2485 ms' │ ' 100 ms' │ ' 48 ms' │ ' 2.08 x' │ │ Array_Matrix41000000 │ ' 13116 ms' │ ' 387 ms' │ ' 232 ms' │ ' 1.67 x' │ └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┴──────────────┘

Compression

The following table lists esbuild compiled and minified sizes for each TypeBox module.

┌──────────────────────┬────────────┬────────────┬─────────────┐ │ (index) │ Compiled │ Minified │ Compression │ ├──────────────────────┼────────────┼────────────┼─────────────┤ │ typebox/compiler │ ' 56 kb' │ ' 28 kb' │ '2.01 x' │ │ typebox/conditional │ ' 45 kb' │ ' 18 kb' │ '2.44 x' │ │ typebox/custom │ ' 0 kb' │ ' 0 kb' │ '2.61 x' │ │ typebox/format │ ' 0 kb' │ ' 0 kb' │ '2.66 x' │ │ typebox/guard │ ' 23 kb' │ ' 11 kb' │ '2.07 x' │ │ typebox/value │ ' 80 kb' │ ' 37 kb' │ '2.16 x' │ │ typebox │ ' 12 kb' │ ' 6 kb' │ '1.89 x' │ └──────────────────────┴────────────┴────────────┴─────────────┘

Contribute

TypeBox is open to community contribution. Please ensure you submit an open issue before submitting your pull request. The TypeBox project preferences open community discussion prior to accepting new features.

Keywords

FAQs

What is @sinclair/typebox?

JSONSchema Type Builder with Static Type Resolution for TypeScript

Is @sinclair/typebox popular?

The npm package @sinclair/typebox receives a total of 7,380,811 weekly downloads. As such, @sinclair/typebox popularity was classified as popular.

Is @sinclair/typebox well maintained?

We found that @sinclair/typebox demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.It has 1 open source maintainer collaborating on the project.

Last updated on 25 Nov 2022

Did you know?

Socket installs a Github app to automatically flag issues on every pull request and report the health of your dependencies. Find out what is inside your node modules and prevent malicious activity before you update the dependencies.

Install Socket
Socket

Product

Subscribe to our newsletter

Get open source security insights delivered straight into your inbox. Be the first to learn about new features and product updates.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc