Socket
Socket
Sign inDemoInstall

@sinclair/typebox

Package Overview
Dependencies
0
Maintainers
1
Versions
307
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @sinclair/typebox

JSONSchema Type Builder with Static Type Resolution for TypeScript


Version published
Weekly downloads
29M
decreased by-3.2%
Maintainers
1
Install size
55.9 kB
Created
Weekly downloads
 

Package description

What is @sinclair/typebox?

The @sinclair/typebox package is a TypeScript utility designed to create type-safe schemas with a consistent syntax. It is primarily used for defining data structures with TypeScript types and validating data at runtime using a separate validation library like Ajv.

What are @sinclair/typebox's main functionalities?

Type Creation

Allows the creation of TypeScript types for various data structures such as strings, numbers, objects, arrays, etc. The created types can be used for compile-time type checking and runtime validation.

{"const T = Type.String()"}

Type Composition

Enables the composition of complex types by combining simpler types. This is useful for defining the shape of objects, with optional and required fields.

{"const UserType = Type.Object({ name: Type.String(), age: Type.Optional(Type.Number()) })"}

Type Validation

Provides a way to validate data at runtime against the defined types using a validation library like Ajv. This ensures that the data conforms to the specified schema.

{"const T = Type.String(); const validate = ajv.compile(T); const isValid = validate('hello');"}

Other packages similar to @sinclair/typebox

Readme

Source

TypeBox

JSON Schema Type Builder with Static Type Resolution for TypeScript

npm version GitHub CI

Example

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

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

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

Install

$ npm install @sinclair/typebox --save

Overview

TypeBox is a type builder library that creates in-memory JSON Schema objects that can be statically resolved to TypeScript types. The schemas produced by this library are built to match the static type checking rules of the TypeScript compiler. This allows for a single unified type that can be both statically checked 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.0.3 and above.

License MIT

Contents

Example

The following demonstrates TypeBox's general usage.


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

//--------------------------------------------------------------------------------------------
//
// Let's say you have the following type ...
//
//--------------------------------------------------------------------------------------------

type Record = {
    id: string,
    name: string,
    timestamp: number
}

//--------------------------------------------------------------------------------------------
//
// ...you can construct a JSON schema representation of this type in the following way...
//
//--------------------------------------------------------------------------------------------

const Record = Type.Object({        // const Record = {
    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 a back the static type represenation of it this way.
//
//--------------------------------------------------------------------------------------------

type Record = Static<typeof Record> // type Record = {
                                    //    id: string,
                                    //    name: string,
                                    //    timestamp: number
                                    // }

//--------------------------------------------------------------------------------------------
//
// The type `Record` can now be used as both JSON schema and as a TypeScript type.
//
//--------------------------------------------------------------------------------------------

function receive(record: Record) {

    if(JSON.validate(Record, { id: '42', name: 'dave', timestamp: Date.now() })) {
        // ok...
    }
}

Types

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

┌────────────────────────────────┬─────────────────────────────┬─────────────────────────────┐
│ TypeBoxTypeScriptJSON Schema                 │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Any()           │ type T = anyconst T = { }               │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Unknown()       │ type T = unknownconst 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('foo')  │ type T = 'foo'const T = {                 │
│                                │                             │    type: 'string',          │
│                                │                             │    enum: ['foo']            │
│                                │                             │ }                           │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Array(          │ type T = number[]           │ const T = {                 │
│    Type.Number()               │                             │    type: 'array',           │
│ )                              │                             │    items: {                 │
│                                │                             │      type: 'number'         │
│                                │                             │    }                        │
│                                │                             │ }                           │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Dict(           │ type T = {                  │ const T = {                 │
│    Type.Number()               │      [key: string]          │    type: 'object'           │
│ )                              │ } : numberadditionalProperties: {  │
│   	                         │                             │      type: 'number'         │
│   	                         │                             │    }                        │
│   	                         │                             │ }                           │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Object({        │ type T = {                  │ const T = {                 │
│   name:  Type.String(),        │    name: string,            │   type: 'object',           │
│   email: Type.String(),        │    email: stringproperties: {             │
│ })	                         │ }                           │      name: {                │
│   	                         │                             │        type: 'string'       │
│   	                         │                             │      },                     │
│   	                         │                             │      email: {               │
│                                │                             │        type: 'string'       │
│   	                         │                             │      }                      │
│   	                         │                             │   }                         │
│   	                         │                             │ }                           │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Tuple([         │ type T = [string, number]   │ const T = {                 │
│   Type.String(),               │                             │    type: 'array',           │
│   Type.Number()                │                             │    items: [                 │
│ ])                             │                             │       {                     │
│   	                         │                             │         type: 'string'      │
│   	                         │                             │       }, {                  │
│   	                         │                             │         type: 'number'      │
│   	                         │                             │       }                     │
│   	                         │                             │    ],                       │
│   	                         │                             │    additionalItems: false,  │
│   	                         │                             │    minItems: 2,             │
│   	                         │                             │    maxItems: 2,             │
│   	                         │                             │ }                           |
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ enum Foo {                     │ enum Foo {                  │ const T = {                 │
│   A,                           │   A,                        │    enum: [0, 1]             │
│   B                            │   B                         │ }                           │
│ }                              │ }                           │                             │
│                                │                             │                             │
│ type T = Type.Enum(Foo)        │ type T = Foo                │                             │
│                                │                             │                             │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ 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({               │    a: stringallOf: [{                 │
│         a: Type.String()       │ } & {                       │     type: 'object',         │
│    }),                         │    b: numberproperties: {           │
│    Type.Object({               │ }                           │        a: {                 │
│       b: Type.Number()         │                             │          type: 'string'     │
│   })                           │                             │        }                    │
│ })                             │                             │     },                      │
│                                │                             │     required: ['a']         │
│                                │                             │   }, {                      │
│                                │                             │     type: 'object',         │
│                                │                             │     properties: {           │
│                                │                             │       b: {                  │
│                                │                             │         type: 'number'      │
│                                │                             │       }                     │
│                                │                             │     },                      │
│                                │                             │     required:['b']          │
│                                │                             │   }]                        │
│                                │                             │ }                           │
└────────────────────────────────┴─────────────────────────────┴─────────────────────────────┘

Modifiers

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

┌────────────────────────────────┬─────────────────────────────┬─────────────────────────────┐
│ TypeBoxTypeScriptJSON Schema                 │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Object({        │ type T = {                  │ const T = {                 │
│   name: Type.Optional(         │    name?: string,           │   type: 'object',           │
│      Type.String(),            │ }                           │   properties: {             │
│   )	                         │                             │      name: {                │
│ })  	                         │                             │        type: 'string'       │
│   	                         │                             │      }                      │
│   	                         │                             │   },                        │
│                                │                             │   required: []              │
│   	                         │                             │ }                           │
│   	                         │                             │                             │
│   	                         │                             │                             │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ 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'       │
│   	                         │                             │      }                      │
│   	                         │                             │   },                        │
│                                │                             │   required: []              │
│   	                         │                             │ }                           │
│   	                         │                             │                             │
│   	                         │                             │                             │
└────────────────────────────────┴─────────────────────────────┴─────────────────────────────┘

Functions

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.

┌────────────────────────────────┬─────────────────────────────┬─────────────────────────────┐
│ TypeBoxTypeScriptExtended Schema             │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Constructor([   │ type T = new (              │ const T = {                 │
|    Type.String(),              │  arg0: string,              │   type: 'constructor'       │
│    Type.Number(),              │  arg1: numberarguments: [{             │
│ ], Type.Boolean())             │ ) => booleantype: 'string'         │
│                                │                             │   }, {                      │
│                                │                             │      type: 'number'         │
│                                │                             │   }],                       │
│                                │                             │   returns: {                │
│                                │                             │      type: 'boolean'        │
│                                │                             │   }                         │
│                                │                             │ }                           │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Function([      │ type T = (                  │ const T = {                 │
|    Type.String(),              │  arg0: string,              │   type : 'function',        │
│    Type.Number(),              │  arg1: numberarguments: [{             │
│ ], Type.Boolean())             │ ) => booleantype: '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 = undefinedconst T = {                 │
|                                │                             │   type: 'undefined'         │
|                                │                             │ }                           │
├────────────────────────────────┼─────────────────────────────┼─────────────────────────────┤
│ const T = Type.Void()          │ type T = voidconst T = {                 │
|                                │                             │   type: 'void'              │
|                                │                             │ }                           │
└────────────────────────────────┴─────────────────────────────┴─────────────────────────────┘

Interfaces

It is possible to create interfaces from TypeBox types. Consider the following code that creates a ControllerInterface type that has a single function createRecord(...). The following code is typical TypeScript that describes an interface.

interface CreateRecordRequest {
    data: string
}

interface CreateRecordResponse {
    id: string
}

interface ControllerInterface {
    createRecord(record: CreateRecordRequest): Promise<CreateRecordResponse>
}

class Controller implements ControllerInterface {
    async createRecord(record: CreateRecordRequest): Promise<CreateRecordResponse> {
        return { id: '1' }
    }
}

The following is the TypeBox equivalent.


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

type CreateRecordRequest = Static<typeof CreateRecordRequest>
const CreateRecordRequest = Type.Object({
    data: Type.String()
})
type CreateRecordResponse = Static<typeof CreateRecordResponse>
const CreateRecordResponse = Type.Object({
    id: Type.String()
})

type ControllerInterface = Static<typeof ControllerInterface>
const IController = Type.Object({
    createRecord: Type.Function([CreateRecordRequest], Type.Promise(CreateRecordResponse))
})

class Controller implements ControllerInterface {
    async createRecord(record: CreateRecordRequest): Promise<CreateRecordResponse> {
        return { id: '1' }
    }
}

Because TypeBox encodes the type information as JSON schema, it now becomes possible to reflect on the JSON schema to produce sharable metadata that can be used as machine readable documentation.


console.log(JSON.stringify(ControllerInterface, null, 2))
// outputs:
//
// {
//   "type": "object",
//   "properties": {
//     "createRecord": {
//       "type": "function",
//       "arguments": [
//         {
//           "type": "object",
//           "properties": {
//             "data": {
//               "type": "string"
//             }
//           },
//           "required": [
//             "data"
//           ]
//         }
//       ],
//       "returns": {
//         "type": "promise",
//         "item": {
//           "type": "object",
//           "properties": {
//             "id": {
//               "type": "string"
//             }
//           },
//           "required": [
//             "id"
//           ]
//         }
//       }
//     }
//   },
//   "required": [
//     "createRecord"
//   ]
// }

Validation

TypeBox does not provide JSON schema validation out of the box and expects users to select an appropriate JSON schema validation library. TypeBox schemas should match JSON Schema draft 6. So any validation library capable of draft 6 should be fine.

A good validation library to use is AJV. The following demonstrates basic usage.

import { Type } from '@sinclair/typebox'

import * as Ajv from 'ajv'

const User = Type.Object({
    name:  Type.String(),
    email: Type.String({ format: 'email' })
})

const ajv = new Ajv()

const user = { name: 'dave', email: 'dave@domain.com' }

const isValid = ajv.validate(User, user)
//
// -> true

Keywords

FAQs

Last updated on 15 Nov 2020

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc