Skip to main content
Deno 2 is finally here πŸŽ‰οΈ
Learn more

TypeBox

JSON Schema Type Builder with Static Type Resolution for TypeScript

npm version GitHub CI

Install

Node

$ npm install @sinclair/typebox --save

Deno

import { Static, Type } from 'https://deno.land/x/typebox/src/typebox.ts'

Example

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

const T = Type.String()     // const T = { "type": "string" }

type T = Static<typeof T>   // type T = string

Overview

TypeBox is a 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 allows one to create a unified type that can be both statically asserted by the TypeScript compiler and runtime asserted using standard JSON Schema validation.

TypeBox can be used as a simple tool to build up complex schemas or integrated into RPC or REST services to help validate JSON data received over the wire. TypeBox does not provide any JSON schema validation. Please use libraries such as AJV to validate schemas built with this library.

Requires TypeScript 4.3.5 and above.

License MIT

Contents

Usage

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

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

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ TypeBox                        β”‚ TypeScript                  β”‚ JSON Schema                    β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Any()           β”‚ type T = any                β”‚ const T = { }                  β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Unknown()       β”‚ type T = unknown            β”‚ const T = { }                  β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.String()        β”‚ type T = string             β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚    type: 'string'              β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Number()        β”‚ type T = number             β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚    type: 'number'              β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Integer()       β”‚ type T = number             β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚    type: 'integer'             β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Boolean()       β”‚ type T = boolean            β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚    type: 'boolean'             β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Null()          β”‚ type T = null               β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚    type: 'null'                β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.RegEx(/foo/)    β”‚ type T = string             β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚    type: 'string',             β”‚
β”‚                                β”‚                             β”‚    pattern: 'foo'              β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Literal(42)     β”‚ type T = 42                 β”‚ const 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,                β”‚    enum: ['x', 'y'],           β”‚
β”‚     x: Type.Number(),          β”‚   y: number                 β”‚    type: 'string'              β”‚
β”‚     y: Type.Number()           β”‚ }                           β”‚ }                              β”‚
β”‚   })                           β”‚                             β”‚                                β”‚
β”‚ )                              β”‚                             β”‚                                β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Union([         β”‚ type T = string | number    β”‚ const T = {                    β”‚
β”‚   Type.String(),               β”‚                             β”‚    anyOf: [{                   β”‚
β”‚   Type.Number()                β”‚                             β”‚       type: 'string'           β”‚
β”‚ ])                             β”‚                             β”‚    }, {                        β”‚
β”‚                                β”‚                             β”‚       type: 'number'           β”‚
β”‚                                β”‚                             β”‚    }]                          β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Intersect([     β”‚ type T = {                  β”‚ const T = {                    β”‚
β”‚    Type.Object({               β”‚    x: number                β”‚    allOf: [{                   β”‚
β”‚       x: Type.Number()         β”‚ } & {                       β”‚       type: 'object',          β”‚
β”‚    }),                         β”‚    y: number                β”‚       properties: {            β”‚
β”‚    Type.Object({               β”‚ }                           β”‚          x: {                  β”‚
β”‚       y: Type.Number()         β”‚                             β”‚            type: 'number'      β”‚
β”‚   })                           β”‚                             β”‚          }                     β”‚
β”‚ })                             β”‚                             β”‚       },                       β”‚
β”‚                                β”‚                             β”‚       required: ['x']          β”‚
β”‚                                β”‚                             β”‚    }, {                        β”‚
β”‚                                β”‚                             β”‚       type: 'object',          β”‚
β”‚                                β”‚                             β”‚       properties: {            β”‚
β”‚                                β”‚                             β”‚          y: {                  β”‚
β”‚                                β”‚                             β”‚            type: 'number'      β”‚
β”‚                                β”‚                             β”‚          }                     β”‚
β”‚                                β”‚                             β”‚       },                       β”‚
β”‚                                β”‚                             β”‚       required: ['y']          β”‚
β”‚                                β”‚                             β”‚    }]                          β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Record(         β”‚ type T = {                  β”‚ const T = {                    β”‚
β”‚    Type.String(),              β”‚    [key: string]: number    β”‚    type: 'object',             β”‚
β”‚    Type.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']              β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

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 })

Generic Types

Generic types can be created using functions. The following creates a generic Nullable<T> type.

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

// type Nullable<T> = T | null

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

Reference Types

Types can be referenced with Type.Ref(...). To reference a type, 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'
                                               // }

It can sometimes be helpful to organize shared referenced types under a common namespace. The Type.Namespace(...) function can be used to create a shared definition container for related types. The following creates a Math3D container and a Vertex structure that references types in the container.

const Math3D = Type.Namespace({                 //  const Math3D = {
  Vector4: Type.Object({                        //    $id: 'Math3D',
    x: Type.Number(),                           //    $defs: {
    y: Type.Number(),                           //      Vector4: {
    z: Type.Number(),                           //        type: 'object',
    w: Type.Number()                            //        properties: {
  }),                                           //          x: { type: 'number' },
  Vector3: Type.Object({                        //          y: { type: 'number' },
    x: Type.Number(),                           //          z: { type: 'number' },
    y: Type.Number(),                           //          w: { type: 'number' }
    z: Type.Number()                            //        },
  }),                                           //        required: ['x', 'y', 'z', 'w']
  Vector2: Type.Object({                        //      },
    x: Type.Number(),                           //      Vector3: {
    y: Type.Number()                            //        type: 'object',
  })                                            //        properties: {
}, { $id: 'Math3D' })                           //          x: { 'type': 'number' },
                                                //          y: { 'type': 'number' },
                                                //          z: { 'type': 'number' }
                                                //        },
                                                //        required: ['x', 'y', 'z']
                                                //      },
                                                //      Vector2: {
                                                //        type: 'object',
                                                //        properties: {
                                                //          x: { 'type': 'number' },
                                                //          y: { 'type': 'number' },
                                                //        },
                                                //        required: ['x', 'y']
                                                //      }
                                                //    }
                                                //  }
                                                     
const Vertex = Type.Object({                    //  const Vertex = {
    position: Type.Ref(Math3D, 'Vector4'),      //    type: 'object',
    normal:   Type.Ref(Math3D, 'Vector3'),      //    properties: {
    uv:       Type.Ref(Math3D, 'Vector2')       //      position: { $ref: 'Math3D#/$defs/Vector4' },
})                                              //      normal: { $ref: 'Math3D#/$defs/Vector3' },
                                                //      uv: { $ref: 'Math3D#/$defs/Vector2' }
                                                //    },
                                                //    required: ['position', 'normal', 'uv']
                                                //  }

Recursive Types

Recursive types can be created with the Type.Rec(...) function. The following creates a Node type that contains an array of inner Nodes. Note that due to current restrictions on TypeScript inference, it is not possible for TypeBox to statically infer for recursive types. TypeBox will infer the inner recursive type as any.

const Node = Type.Rec(Self => Type.Object({    // const Node = {
  id:    Type.String(),                        //   $id: 'Node',
  nodes: Type.Array(Self),                     //   $ref: 'Node#/$defs/self',
}), { $id: 'Node' })                           //   $defs: {
                                               //     self: {
                                               //       type: 'object',
                                               //       properties: {
                                               //         id: {
                                               //           type: 'string'
                                               //         },
                                               //         nodes: {
                                               //            type: 'array',
                                               //            items: {
                                               //              $ref: 'Node#/$defs/self'
                                               //            }
                                               //         }
                                               //      }
                                               //    }
                                               // }

type Node = Static<typeof Node>                // type Node = {
                                               //   id: string
                                               //   nodes: any[]
                                               // }

function visit(node: Node) {
    for(const inner of node.nodes) {
        visit(inner as Node)                   // Assert inner as Node
    }
}

Extended Types

In addition to JSON schema types, TypeBox provides several extended types that allow for function and constructor types to be composed. These additional types are not valid JSON Schema and will not validate using typical JSON Schema validation. However, these types can be used to frame JSON schema and describe callable interfaces that may receive JSON validated data. These types are as follows.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ TypeBox                        β”‚ TypeScript                  β”‚ Extended Schema                β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Constructor([   β”‚ type T = new (              β”‚ const T = {                    β”‚
β”‚    Type.String(),              β”‚  arg0: string,              β”‚   type: 'constructor'          β”‚
β”‚    Type.Number(),              β”‚  arg1: number               β”‚   arguments: [{                β”‚
β”‚ ], Type.Boolean())             β”‚ ) => boolean                β”‚      type: 'string'            β”‚
β”‚                                β”‚                             β”‚   }, {                         β”‚
β”‚                                β”‚                             β”‚      type: 'number'            β”‚
β”‚                                β”‚                             β”‚   }],                          β”‚
β”‚                                β”‚                             β”‚   returns: {                   β”‚
β”‚                                β”‚                             β”‚      type: 'boolean'           β”‚
β”‚                                β”‚                             β”‚   }                            β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Function([      β”‚ type T = (                  β”‚ const T = {                    β”‚
|    Type.String(),              β”‚  arg0: string,              β”‚   type : 'function',           β”‚
β”‚    Type.Number(),              β”‚  arg1: number               β”‚   arguments: [{                β”‚
β”‚ ], Type.Boolean())             β”‚ ) => boolean                β”‚      type: 'string'            β”‚
β”‚                                β”‚                             β”‚   }, {                         β”‚
β”‚                                β”‚                             β”‚      type: 'number'            β”‚
β”‚                                β”‚                             β”‚   }],                          β”‚
β”‚                                β”‚                             β”‚   returns: {                   β”‚
β”‚                                β”‚                             β”‚      type: 'boolean'           β”‚
β”‚                                β”‚                             β”‚   }                            β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Promise(        β”‚ type T = Promise<string>    β”‚ const T = {                    β”‚
β”‚    Type.String()               β”‚                             β”‚   type: 'promise',             β”‚
β”‚ )                              β”‚                             β”‚   item: {                      β”‚
β”‚                                β”‚                             β”‚      type: 'string'            β”‚
β”‚                                β”‚                             β”‚   }                            β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Undefined()     β”‚ type T = undefined          β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚   type: 'undefined'            β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ const T = Type.Void()          β”‚ type T = void               β”‚ const T = {                    β”‚
β”‚                                β”‚                             β”‚   type: 'void'                 β”‚
β”‚                                β”‚                             β”‚ }                              β”‚
β”‚                                β”‚                             β”‚                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Strict

TypeBox schemas contain the properties kind and modifier. These properties are provided to enable runtime type reflection on schemas, as well as helping TypeBox apply the appropriate static type inference rules. 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: Symbol(ObjectKind),
})                                            //   type: 'object',
                                              //   properties: {
                                              //     name: {
                                              //       kind: Symbol(StringKind),
                                              //       type: 'string',
                                              //       modifier: Symbol(OptionalModifier)
                                              //     }
                                              //   }
                                              // }

const U = Type.Strict(T)                      // const U = {
                                              //     type: 'object', 
                                              //     properties: { 
                                              //         name: { 
                                              //             type: 'string' 
                                              //         } 
                                              //     } 
                                              // }

Validation

TypeBox does not provide JSON schema validation so users will need to select an appropriate JSON Schema validator for their needs. TypeBox schemas target JSON Schema draft 2019-09 so any validator capable of draft 2019-09 should be fine. A good library to use for validation in JavaScript environments is AJV. The following example shows setting up AJV 7 to work with TypeBox.

$ npm install ajv ajv-formats --save
//--------------------------------------------------------------------------------------------
//
// Import the 2019 compliant validator from AJV
//
//--------------------------------------------------------------------------------------------

import { Type }   from '@sinclair/typebox'
import addFormats from 'ajv-formats'
import Ajv        from 'ajv/dist/2019'

//--------------------------------------------------------------------------------------------
//
// Setup AJV validator with the following options and formats
//
//--------------------------------------------------------------------------------------------

const ajv = addFormats(new Ajv({}), [
    'date-time', 
    'time', 
    'date', 
    'email',  
    'hostname', 
    'ipv4', 
    'ipv6', 
    'uri', 
    'uri-reference', 
    'uuid',
    'uri-template', 
    'json-pointer', 
    'relative-json-pointer', 
    'regex'
]).addKeyword('kind')
  .addKeyword('modifier')

//--------------------------------------------------------------------------------------------
//
// Create a TypeBox type
//
//--------------------------------------------------------------------------------------------

const User = Type.Object({
    userId: Type.String({ format: 'uuid' }),
    email:  Type.String({ format: 'email' }),
    online: Type.Boolean(),
}, { additionalProperties: false })

//--------------------------------------------------------------------------------------------
//
// Validate Data
//
//--------------------------------------------------------------------------------------------

const ok = ajv.validate(User, { 
    userId: '68b4b1d8-0db6-468d-b551-02069a692044', 
    email:  'dave@domain.com',
    online:  true
}) // -> ok

Please refer to the official AJV documentation for additional information on using AJV.

OpenAPI

TypeBox can be used to create schemas for OpenAPI, however users should be mindful of some disparities between the JSON Schema and OpenAPI for versions prior to OpenAPI 3.1. Two common instances where OpenAPI diverges is the handling nullable and string enum schemas types. The following shows how you can use TypeBox to construct these types.

import { Type, Static, TNull, TLiteral, TUnion, TSchema } from '@sinclair/typebox'

//--------------------------------------------------------------------------------------------
//
// Nullable<T>
//
//--------------------------------------------------------------------------------------------

function Nullable<T extends TSchema>(schema: T): TUnion<[T, TNull]> {
    return { ...schema, nullable: true } as any
}

const T = Nullable(Type.String())              // const T = {
                                               //   type: 'string',
                                               //   nullable: true
                                               // }

type T = Static<typeof T>                      // type T = string | null

//--------------------------------------------------------------------------------------------
//
// StringUnion<[...]>
//
//--------------------------------------------------------------------------------------------

type IntoStringUnion<T> = {[K in keyof T]: T[K] extends string ? TLiteral<T[K]>: never }

function StringUnion<T extends string[]>(values: [...T]): TUnion<IntoStringUnion<T>> {
    return { enum: values } as any
}

const T = StringUnion(['A', 'B', 'C'])          // const T = {
                                                //    enum: ['A', 'B', 'C']
                                                // }

type T = Static<typeof T>                       // type T = 'A' | 'B' | 'C'