Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
@sinclair/typebox
Advanced tools
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.
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');"}
Joi is a powerful schema description language and data validator for JavaScript. It allows for detailed descriptions of data structures with a wide range of validation options. Compared to @sinclair/typebox, Joi has a more extensive API and built-in validation without the need for an external library.
Yup is a JavaScript schema builder for value parsing and validation. It defines a schema with an expressive API and handles both validation and error messages. Unlike @sinclair/typebox, Yup includes its own validation methods and does not rely on TypeScript for type definitions.
Zod is a TypeScript-first schema declaration and validation library. It offers a similar experience to @sinclair/typebox by leveraging TypeScript for type safety while also providing runtime validation. Zod's API is designed to be more concise and it includes its own validation logic.
$ npm install @sinclair/typebox --save
import { Static, Type } from 'npm:@sinclair/typebox'
import { Static, Type } from 'https://esm.sh/@sinclair/typebox'
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
// }
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.
This library 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
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...
}
}
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.
The following table lists the Standard TypeBox types.
ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β 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, β anyOf: [{ β
β x: Type.Number(), β y: number β type: 'string', β
β y: Type.Number() β } β const: 'x' β
β }) β β }, { β
β ) β β type: 'string', β
β β β const: 'y' β
β β β }] β
β β β } β
β β β β
ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ€
β 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 β type: '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 = never β const 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'] β
β β β } β
β β β β
ββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ
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 = Uint8Array β const T = { β
β β β type: 'object', β
β β β instanceOf: 'Uint8Array' β
β β β } β
β β β β
ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ€
β const T = Type.Date() β type T = Date β const T = { β
β β β type: 'object', β
β β β instanceOf: 'Date' β
β β β } β
β β β β
ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ€
β const T = Type.Undefined() β type T = undefined β const T = { β
β β β type: 'null', β
β β β typeOf: 'Undefined' β
β β β } β
β β β β
ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ€
β const T = Type.Void() β type T = void β const T = { β
β β β type: 'null' β
β β β typeOf: 'Void' β
β β β } β
β β β β
ββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ
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' β
β β β } β
β β β } β
β β β } β
β β β β
ββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ
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 })
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'
// }
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
}
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
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') β β }] β
β ]) β β } β
β ) β β β
β β β β
ββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ
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'
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
}
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'
// }
// }
// }
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'
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 }
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 }
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
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 }
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 }
)
Use the Hash function to create a FNV1A-64 non cryptographic hash of a value.
const A = Value.Hash({ x: 1, y: 2, z: 3 }) // const A = 2910466848807138541n
const B = Value.Hash({ x: 1, y: 4, z: 3 }) // const B = 1418369778807423581n
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' }
// ]
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 }
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'
// }]
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 }
TypeBox constructs JSON Schema draft 6 compliant schematics and can be used with any validator that supports this specification. In JavaScript, an ideal validator to use is Ajv which supports draft 6 as well as more recent revisions to the specification. In addition to Ajv, TypeBox provides an optional built in type compiler which can offer faster runtime type compilation, as well as providing high performance data validation for TypeBox types only.
The following sections detail using these validators.
The following shows the recommended setup for Ajv.
$ npm install ajv ajv-formats --save
import { Type } from '@sinclair/typebox'
import addFormats from 'ajv-formats'
import Ajv from 'ajv'
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'
])
const C = ajv.compile(Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number()
}))
const R = C({ x: 1, y: 2, z: 3 }) // const R = true
The TypeCompiler is a Just-In-Time (JIT) runtime compiler that can be used to convert TypeBox types into fast validation routines. This compiler is specifically tuned for fast compilation and validation for TypeBox types only.
The TypeCompiler 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
Use Errors(...)
to generate diagnostics for a value. The Errors(...)
function will run an exhaustive check across the value and yield any error found. For performance, this function should only be called after failed Check(...)
.
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')
// )
// }
TypeBox provides an extensible TypeSystem module that enables developers to define additional types above and beyond the built in type set. This module also allows developers to define custom string formats as well as override certain type checking behaviours.
The TypeSystem module is provided as an optional import.
import { TypeSystem } from '@sinclair/typebox/system'
Use the CreateType(...)
function to specify custom type. This function will return a type factory function that can be used to construct the type. The following creates and registers a BigNumber type which will statically infer as bigint
.
//--------------------------------------------------------------------------------------------
//
// Use TypeSystem.CreateType(...) to define and return a type factory function
//
//--------------------------------------------------------------------------------------------
type BigNumberOptions = { minimum?: bigint; maximum?: bigint }
const BigNumber = TypeSystem.CreateType<bigint, BigNumberOptions>(
'BigNumber',
(options, value) => {
if (typeof value !== 'bigint') return false
if (options.maximum !== undefined && value > options.maximum) return false
if (options.minimum !== undefined && value < options.minimum) return false
return true
}
)
//--------------------------------------------------------------------------------------------
//
// Use the custom type like any other type
//
//--------------------------------------------------------------------------------------------
const T = BigNumber({ minimum: 10n, maximum: 20n }) // const T = {
// minimum: 10n,
// maximum: 20n,
// [Symbol(TypeBox.Kind)]: 'BigNumber'
// }
const C = TypeCompiler.Compile(T)
const X = C.Check(15n) // const X = true
const Y = C.Check(5n) // const Y = false
const Z = C.Check(25n) // const Z = false
Use the CreateFormat(...)
function to specify user defined string formats. The following creates a custom string format that checks for lowercase.
//--------------------------------------------------------------------------------------------
//
// Use TypeSystem.CreateFormat(...) to define a custom string format
//
//--------------------------------------------------------------------------------------------
TypeSystem.CreateFormat('lowercase', value => value === value.toLowerCase())
//--------------------------------------------------------------------------------------------
//
// Use the format by creating string types with the 'format' option
//
//--------------------------------------------------------------------------------------------
const T = Type.String({ format: 'lowercase' })
const A = Value.Check(T, 'action') // const A = true
const B = Value.Check(T, 'ACTION') // const B = false
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.
This benchmark measures compilation performance for varying types. You can review this benchmark here.
ββββββββββββββββββββ¬βββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ
β (index) β Iterations β Ajv β TypeCompiler β Performance β
ββββββββββββββββββββΌβββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββ€
β Number β 2000 β ' 451 ms' β ' 16 ms' β ' 28.19 x' β
β String β 2000 β ' 338 ms' β ' 14 ms' β ' 24.14 x' β
β Boolean β 2000 β ' 297 ms' β ' 13 ms' β ' 22.85 x' β
β Null β 2000 β ' 265 ms' β ' 8 ms' β ' 33.13 x' β
β RegEx β 2000 β ' 492 ms' β ' 18 ms' β ' 27.33 x' β
β ObjectA β 2000 β ' 2744 ms' β ' 55 ms' β ' 49.89 x' β
β ObjectB β 2000 β ' 3005 ms' β ' 44 ms' β ' 68.30 x' β
β Tuple β 2000 β ' 1283 ms' β ' 26 ms' β ' 49.35 x' β
β Union β 2000 β ' 1263 ms' β ' 27 ms' β ' 46.78 x' β
β Vector4 β 2000 β ' 1622 ms' β ' 23 ms' β ' 70.52 x' β
β Matrix4 β 2000 β ' 888 ms' β ' 12 ms' β ' 74.00 x' β
β Literal_String β 2000 β ' 344 ms' β ' 14 ms' β ' 24.57 x' β
β Literal_Number β 2000 β ' 389 ms' β ' 8 ms' β ' 48.63 x' β
β Literal_Boolean β 2000 β ' 374 ms' β ' 9 ms' β ' 41.56 x' β
β Array_Number β 2000 β ' 710 ms' β ' 12 ms' β ' 59.17 x' β
β Array_String β 2000 β ' 739 ms' β ' 9 ms' β ' 82.11 x' β
β Array_Boolean β 2000 β ' 732 ms' β ' 7 ms' β ' 104.57 x' β
β Array_ObjectA β 2000 β ' 3733 ms' β ' 42 ms' β ' 88.88 x' β
β Array_ObjectB β 2000 β ' 3602 ms' β ' 42 ms' β ' 85.76 x' β
β Array_Tuple β 2000 β ' 2204 ms' β ' 20 ms' β ' 110.20 x' β
β Array_Union β 2000 β ' 1533 ms' β ' 24 ms' β ' 63.88 x' β
β Array_Vector4 β 2000 β ' 2263 ms' β ' 21 ms' β ' 107.76 x' β
β Array_Matrix4 β 2000 β ' 1576 ms' β ' 14 ms' β ' 112.57 x' β
ββββββββββββββββββββ΄βββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ
This benchmark measures validation performance for varying types. You can review this benchmark here.
ββββββββββββββββββββ¬βββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ
β (index) β Iterations β ValueCheck β Ajv β TypeCompiler β Performance β
ββββββββββββββββββββΌβββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββ€
β Number β 1000000 β ' 30 ms' β ' 7 ms' β ' 6 ms' β ' 1.17 x' β
β String β 1000000 β ' 23 ms' β ' 21 ms' β ' 11 ms' β ' 1.91 x' β
β Boolean β 1000000 β ' 22 ms' β ' 21 ms' β ' 10 ms' β ' 2.10 x' β
β Null β 1000000 β ' 27 ms' β ' 20 ms' β ' 10 ms' β ' 2.00 x' β
β RegEx β 1000000 β ' 163 ms' β ' 47 ms' β ' 38 ms' β ' 1.24 x' β
β ObjectA β 1000000 β ' 654 ms' β ' 41 ms' β ' 24 ms' β ' 1.71 x' β
β ObjectB β 1000000 β ' 1173 ms' β ' 59 ms' β ' 41 ms' β ' 1.44 x' β
β Tuple β 1000000 β ' 124 ms' β ' 24 ms' β ' 17 ms' β ' 1.41 x' β
β Union β 1000000 β ' 332 ms' β ' 26 ms' β ' 16 ms' β ' 1.63 x' β
β Recursive β 1000000 β ' 3129 ms' β ' 412 ms' β ' 102 ms' β ' 4.04 x' β
β Vector4 β 1000000 β ' 147 ms' β ' 26 ms' β ' 13 ms' β ' 2.00 x' β
β Matrix4 β 1000000 β ' 576 ms' β ' 41 ms' β ' 28 ms' β ' 1.46 x' β
β Literal_String β 1000000 β ' 51 ms' β ' 21 ms' β ' 10 ms' β ' 2.10 x' β
β Literal_Number β 1000000 β ' 47 ms' β ' 21 ms' β ' 11 ms' β ' 1.91 x' β
β Literal_Boolean β 1000000 β ' 47 ms' β ' 21 ms' β ' 10 ms' β ' 2.10 x' β
β Array_Number β 1000000 β ' 490 ms' β ' 33 ms' β ' 18 ms' β ' 1.83 x' β
β Array_String β 1000000 β ' 502 ms' β ' 31 ms' β ' 25 ms' β ' 1.24 x' β
β Array_Boolean β 1000000 β ' 465 ms' β ' 33 ms' β ' 27 ms' β ' 1.22 x' β
β Array_ObjectA β 1000000 β ' 15463 ms' β ' 2470 ms' β ' 2052 ms' β ' 1.20 x' β
β Array_ObjectB β 1000000 β ' 18047 ms' β ' 2497 ms' β ' 2348 ms' β ' 1.06 x' β
β Array_Tuple β 1000000 β ' 1958 ms' β ' 99 ms' β ' 77 ms' β ' 1.29 x' β
β Array_Union β 1000000 β ' 5348 ms' β ' 254 ms' β ' 89 ms' β ' 2.85 x' β
β Array_Recursive β 1000000 β ' 54643 ms' β ' 8870 ms' β ' 1158 ms' β ' 7.66 x' β
β Array_Vector4 β 1000000 β ' 2724 ms' β ' 105 ms' β ' 48 ms' β ' 2.19 x' β
β Array_Matrix4 β 1000000 β ' 13821 ms' β ' 437 ms' β ' 266 ms' β ' 1.64 x' β
ββββββββββββββββββββ΄βββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ
The following table lists esbuild compiled and minified sizes for each TypeBox module.
ββββββββββββββββββββββββ¬βββββββββββββ¬βββββββββββββ¬ββββββββββββββ
β (index) β Compiled β Minified β Compression β
ββββββββββββββββββββββββΌβββββββββββββΌβββββββββββββΌββββββββββββββ€
β typebox/compiler β ' 65.4 kb' β ' 32.2 kb' β '2.03 x' β
β typebox/conditional β ' 45.5 kb' β ' 18.6 kb' β '2.45 x' β
β typebox/custom β ' 0.6 kb' β ' 0.2 kb' β '2.61 x' β
β typebox/format β ' 0.6 kb' β ' 0.2 kb' β '2.66 x' β
β typebox/guard β ' 23.8 kb' β ' 11.4 kb' β '2.08 x' β
β typebox/hash β ' 4.2 kb' β ' 1.8 kb' β '2.30 x' β
β typebox/system β ' 14.0 kb' β ' 7.1 kb' β '1.96 x' β
β typebox/value β ' 90.0 kb' β ' 41.8 kb' β '2.15 x' β
β typebox β ' 12.0 kb' β ' 6.4 kb' β '1.89 x' β
ββββββββββββββββββββββββ΄βββββββββββββ΄βββββββββββββ΄ββββββββββββββ
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.
FAQs
Json Schema Type Builder with Static Type Resolution for TypeScript
The npm package @sinclair/typebox receives a total of 11,903,364 weekly downloads. As such, @sinclair/typebox popularity was classified as popular.
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.
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.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.