@sinclair/typebox
v0.34.7
Published
Json Schema Type Builder with Static Type Resolution for TypeScript
Downloads
144,186,142
Maintainers
Readme
Install
$ npm install @sinclair/typebox --save
Example
import { Type, type Static } from '@sinclair/typebox'
const T = Type.Object({ // const T = {
x: Type.Number(), // type: 'object',
y: Type.Number(), // required: ['x', 'y', 'z'],
z: Type.Number() // properties: {
}) // x: { type: 'number' },
// y: { type: 'number' },
// z: { type: 'number' }
// }
// }
type T = Static<typeof T> // type T = {
// x: number,
// y: number,
// z: number
// }
Overview
TypeBox is a runtime type builder that creates in-memory Json Schema objects that infer as TypeScript types. The schematics produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox offers a unified type that can be statically checked by TypeScript and runtime asserted using standard Json Schema validation.
This library is designed to allow Json Schema to compose similar to how types compose within TypeScript's type system. It can be used as a simple tool to build up complex schematics or integrated into REST and RPC services to help validate data received over the wire.
License MIT
Contents
- Install
- Overview
- Usage
- Types
- Syntax
- Values
- TypeRegistry
- TypeCheck
- TypeSystem
- Error Function
- Workbench
- Codegen
- Ecosystem
- Benchmark
- Contribute
Usage
The following shows general usage.
import { Type, type Static } 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
// }
//--------------------------------------------------------------------------------------------
//
// ... or use the type to parse JavaScript values.
//
//--------------------------------------------------------------------------------------------
import { Value } from '@sinclair/typebox/value'
const R = Value.Parse(T, value) // const R: {
// id: string,
// name: string,
// timestamp: number
// }
Types
TypeBox types are Json Schema fragments that compose into more complex types. Each fragment is structured such that any Json Schema compliant validator can runtime assert a value the same way TypeScript will statically assert a type. TypeBox offers a set of Json Types which are used to create Json Schema compliant schematics as well as a JavaScript type set used to create schematics for constructs native to JavaScript.
Json Types
The following table lists the supported Json types. These types are fully compatible with the Json Schema Draft 7 specification.
┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
│ 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.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 │ required: ['x', 'y'], │
│ }) │ } │ properties: { │
│ │ │ x: { │
│ │ │ type: 'number' │
│ │ │ }, │
│ │ │ y: { │
│ │ │ type: 'number' │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ 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.Const({ │ type T = { │ const T = { │
│ x: 1, │ readonly x: 1, │ type: 'object', │
│ y: 2, │ readonly y: 2 │ required: ['x', 'y'], │
│ } as const) │ } │ properties: { │
│ │ │ x: { │
│ │ │ type: 'number', │
│ │ │ const: 1 │
│ │ │ }, │
│ │ │ y: { │
│ │ │ type: 'number', │
│ │ │ const: 2 │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ 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 │ allOf: [{ │
│ x: Type.Number() │ } & { │ type: 'object', │
│ }), │ y: number │ required: ['x'], │
│ Type.Object({ │ } │ properties: { │
│ y: Type.Number() │ │ x: { │
│ }) │ │ type: 'number' │
│ ]) │ │ } │
│ │ │ } │
│ │ │ }, { │
│ │ │ type: 'object', |
│ │ │ required: ['y'], │
│ │ │ properties: { │
│ │ │ y: { │
│ │ │ type: 'number' │
│ │ │ } │
│ │ │ } │
│ │ │ }] │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Composite([ │ type T = { │ const T = { │
│ Type.Object({ │ x: number, │ type: 'object', │
│ x: Type.Number() │ y: number │ required: ['x', 'y'], │
│ }), │ } │ properties: { │
│ Type.Object({ │ │ x: { │
│ y: Type.Number() │ │ type: 'number' │
│ }) │ │ }, │
│ ]) │ │ y: { │
│ │ │ type: 'number' │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Never() │ type T = never │ const T = { │
│ │ │ not: {} │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Not( | type T = unknown │ const T = { │
│ Type.String() │ │ not: { │
│ ) │ │ type: 'string' │
│ │ │ } │
│ │ │ } │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Extends( │ type T = │ const T = { │
│ Type.String(), │ string extends number │ const: false, │
│ Type.Number(), │ ? true │ type: 'boolean' │
│ Type.Literal(true), │ : false │ } │
│ Type.Literal(false) │ │ │
│ ) │ │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Extract( │ type T = Extract< │ const T = { │
│ Type.Union([ │ string | number, │ type: 'string' │
│ Type.String(), │ string │ } │
│ Type.Number(), │ > │ │
│ ]), │ │ │
│ Type.String() │ │ │
│ ) │ │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Exclude( │ type T = Exclude< │ const T = { │
│ Type.Union([ │ string | number, │ type: 'number' │
│ Type.String(), │ string │ } │
│ Type.Number(), │ > │ │
│ ]), │ │ │
│ Type.String() │ │ │
│ ) │ │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Mapped( │ type T = { │ const T = { │
│ Type.Union([ │ [_ in 'x' | 'y'] : number │ type: 'object', │
│ Type.Literal('x'), │ } │ required: ['x', 'y'], │
│ Type.Literal('y') │ │ properties: { │
│ ]), │ │ x: { │
│ () => Type.Number() │ │ type: 'number' │
│ ) │ │ }, │
│ │ │ y: { │
│ │ │ type: 'number' │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const U = Type.Union([ │ type U = 'open' | 'close' │ const T = { │
│ Type.Literal('open'), │ │ type: 'string', │
│ Type.Literal('close') │ type T = `on${U}` │ pattern: '^on(open|close)$' │
│ ]) │ │ } │
│ │ │ │
│ const T = Type │ │ │
│ .TemplateLiteral([ │ │ │
│ Type.Literal('on'), │ │ │
│ U │ │ │
│ ]) │ │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ 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 │ required: ['x', 'y'], │
│ Type.Number() | }> │ properties: { │
│ ), │ │ x: { │
│ y: Type.Optional( │ │ type: 'number' │
│ Type.Number() │ │ }, │
│ ) │ │ y: { │
│ }) │ │ type: 'number' │
│ ) │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Pick( │ type T = Pick<{ │ const T = { │
│ Type.Object({ │ x: number, │ type: 'object', │
│ x: Type.Number(), │ y: number │ required: ['x'], │
│ y: Type.Number() │ }, 'x'> │ properties: { │
│ }), ['x'] | │ x: { │
│ ) │ │ type: 'number' │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Omit( │ type T = Omit<{ │ const T = { │
│ Type.Object({ │ x: number, │ type: 'object', │
│ x: Type.Number(), │ y: number │ required: ['y'], │
│ y: Type.Number() │ }, 'x'> │ properties: { │
│ }), ['x'] | │ y: { │
│ ) │ │ type: 'number' │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Index( │ type T = { │ const T = { │
│ Type.Object({ │ x: number, │ type: 'number' │
│ x: Type.Number(), │ y: string │ } │
│ y: Type.String() │ }['x'] │ │
│ }), ['x'] │ │ │
│ ) │ │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const A = Type.Tuple([ │ type A = [0, 1] │ const T = { │
│ Type.Literal(0), │ type B = [2, 3] │ type: 'array', │
│ Type.Literal(1) │ type T = [ │ items: [ │
│ ]) │ ...A, │ { const: 0 }, │
│ const B = Type.Tuple([ │ ...B │ { const: 1 }, │
| Type.Literal(2), │ ] │ { const: 2 }, │
| Type.Literal(3) │ │ { const: 3 } │
│ ]) │ │ ], │
│ const T = Type.Tuple([ │ │ additionalItems: false, │
| ...Type.Rest(A), │ │ minItems: 4, │
| ...Type.Rest(B) │ │ maxItems: 4 │
│ ]) │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Uncapitalize( │ type T = Uncapitalize< │ const T = { │
│ Type.Literal('Hello') │ 'Hello' │ type: 'string', │
│ ) │ > │ const: 'hello' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Capitalize( │ type T = Capitalize< │ const T = { │
│ Type.Literal('hello') │ 'hello' │ type: 'string', │
│ ) │ > │ const: 'Hello' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Uppercase( │ type T = Uppercase< │ const T = { │
│ Type.Literal('hello') │ 'hello' │ type: 'string', │
│ ) │ > │ const: 'HELLO' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Lowercase( │ type T = Lowercase< │ const T = { │
│ Type.Literal('HELLO') │ 'HELLO' │ type: 'string', │
│ ) │ > │ const: 'hello' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const R = Type.Ref('T') │ type R = unknown │ const R = { $ref: 'T' } │
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
JavaScript Types
TypeBox provides an extended type set that can be used to create schematics for common JavaScript constructs. These types can not be used with any standard Json Schema validator; but can be used to frame schematics for interfaces that may receive Json validated data. JavaScript types are prefixed with the [JavaScript]
jsdoc comment for convenience. The following table lists the supported types.
┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
│ TypeBox │ TypeScript │ Extended Schema │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Constructor([ │ type T = new ( │ const T = { │
│ Type.String(), │ arg0: string, │ type: 'Constructor', │
│ Type.Number() │ arg0: number │ parameters: [{ │
│ ], 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 │ parameters: [{ │
│ ], 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 T = │ const T = { │
│ Type.AsyncIterator( │ AsyncIterableIterator< │ type: 'AsyncIterator', │
│ Type.String() │ string │ items: { │
│ ) │ > │ type: 'string' │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Iterator( │ type T = │ const T = { │
│ Type.String() │ IterableIterator<string> │ type: 'Iterator', │
│ ) │ │ items: { │
│ │ │ type: 'string' │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.RegExp(/abc/i) │ type T = string │ const T = { │
│ │ │ type: 'RegExp' │
│ │ │ source: 'abc' │
│ │ │ flags: 'i' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Uint8Array() │ type T = Uint8Array │ const T = { │
│ │ │ type: 'Uint8Array' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Date() │ type T = Date │ const T = { │
│ │ │ type: 'Date' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Undefined() │ type T = undefined │ const T = { │
│ │ │ type: 'undefined' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Symbol() │ type T = symbol │ const T = { │
│ │ │ type: 'symbol' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.BigInt() │ type T = bigint │ const T = { │
│ │ │ type: 'bigint' │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Void() │ type T = void │ const T = { │
│ │ │ type: 'void' │
│ │ │ } │
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
Import
Import the Type namespace to bring in the full TypeBox type system. This is recommended for most users.
import { Type, type Static } from '@sinclair/typebox'
You can also selectively import types. This enables modern bundlers to tree shake for unused types.
import { Object, Number, String, Boolean, type Static } from '@sinclair/typebox'
Options
You can pass Json Schema options on the last argument of any given type. Option hints specific to each type are provided for convenience.
// String must be an email
const T = Type.String({ // const T = {
format: 'email' // type: 'string',
}) // format: 'email'
// }
// Number must be a multiple of 2
const T = Type.Number({ // const T = {
multipleOf: 2 // type: 'number',
}) // multipleOf: 2
// }
// Array must have at least 5 integer values
const T = Type.Array(Type.Integer(), { // const T = {
minItems: 5 // type: 'array',
}) // minItems: 5,
// items: {
// type: 'integer'
// }
// }
Properties
Object properties can be modified with Readonly and Optional. The following table shows how these modifiers map between TypeScript and Json Schema.
┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
│ TypeBox │ TypeScript │ Json Schema │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Object({ │ type T = { │ const T = { │
│ name: Type.ReadonlyOptional( │ readonly 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.Optional( │ name?: string │ type: 'object', │
│ Type.String() │ } │ properties: { │
│ ) │ │ name: { │
│ }) │ │ type: 'string' │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
Generic Types
Generic types can be created with functions. TypeBox types extend the TSchema interface so you should constrain parameters to this type. The following creates a generic Vector type.
import { Type, type Static, type TSchema } from '@sinclair/typebox'
const Vector = <T extends TSchema>(T: T) =>
Type.Object({ // type Vector<T> = {
x: T, // x: T,
y: T, // y: T,
z: T // z: T
}) // }
const NumberVector = Vector(Type.Number()) // type NumberVector = Vector<number>
Generic types are often used to create aliases for complex types. The following creates a Nullable generic type.
const Nullable = <T extends TSchema>(schema: T) => Type.Union([schema, Type.Null()])
const T = Nullable(Type.String()) // const T = {
// anyOf: [
// { type: 'string' },
// { type: 'null' }
// ]
// }
type T = Static<typeof T> // type T = string | null
Module Types
TypeBox Modules are containers for related types. They provide a referential namespace, enabling types to reference one another via string identifiers. Modules support both singular and mutually recursive referencing within the context of a module, as well as referential computed types (such as Partial + Ref). All Module types must be imported before use. TypeBox represents an imported type with the $defs
Json Schema keyword.
Usage
The following creates a Module with User and PartialUser types. Note that the PartialUser type is specified as a Partial + Ref to the User type. It is not possible to perform a Partial operation directly on a reference, so TypeBox will return a TComputed type that defers the Partial operation until all types are resolved. The TComputed type is evaluated when calling Import on the Module.
// Module with PartialUser and User types
const Module = Type.Module({
PartialUser: Type.Partial(Type.Ref('User')), // TComputed<'Partial', [TRef<'User'>]>
User: Type.Object({ // TObject<{
id: Type.String(), // user: TString,
name: Type.String(), // name: TString,
email: Type.String() // email: TString
}), // }>
})
// Types must be imported before use.
const User = Module.Import('User') // const User: TImport<{...}, 'User'>
type User = Static<typeof User> // type User = {
// id: string,
// name: string,
// email: string
// }
const PartialUser = Module.Import('PartialUser') // const PartialUser: TImport<{...}, 'PartialUser'>
type PartialUser = Static<typeof PartialUser> // type PartialUser = {
// id?: string,
// name?: string,
// email?: string
// }
Template Literal Types
TypeBox supports template literal types with the TemplateLiteral function. This type can be created using a syntax similar to the TypeScript template literal syntax or composed from exterior types. TypeBox encodes template literals as regular expressions which enables the template to be checked by Json Schema validators. This type also supports regular expression parsing that enables template patterns to be used for generative types. The following shows both TypeScript and TypeBox usage.
// TypeScript
type K = `prop${'A'|'B'|'C'}` // type T = 'propA' | 'propB' | 'propC'
type R = Record<K, string> // type R = {
// propA: string
// propB: string
// propC: string
// }
// TypeBox
const K = Type.TemplateLiteral('prop${A|B|C}') // const K: TTemplateLiteral<[
// TLiteral<'prop'>,
// TUnion<[
// TLiteral<'A'>,
// TLiteral<'B'>,
// TLiteral<'C'>,
// ]>
// ]>
const R = Type.Record(K, Type.String()) // const R: TObject<{
// propA: TString,
// propB: TString,
// propC: TString,
// }>
Indexed Access Types
TypeBox supports indexed access types with the Index function. This function enables uniform access to interior property and element types without having to extract them from the underlying schema representation. Index types are supported for Object, Array, Tuple, Union and Intersect types.
const T = Type.Object({ // type T = {
x: Type.Number(), // x: number,
y: Type.String(), // y: string,
z: Type.Boolean() // z: boolean
}) // }
const A = Type.Index(T, ['x']) // type A = T['x']
//
// ... evaluated as
//
// const A: TNumber
const B = Type.Index(T, ['x', 'y']) // type B = T['x' | 'y']
//
// ... evaluated as
//
// const B: TUnion<[
// TNumber,
// TString,
// ]>
const C = Type.Index(T, Type.KeyOf(T)) // type C = T[keyof T]
//
// ... evaluated as
//
// const C: TUnion<[
// TNumber,
// TString,
// TBoolean
// ]>
Mapped Types
TypeBox supports mapped types with the Mapped function. This function accepts two arguments, the first is a union type typically derived from KeyOf, the second is a mapping function that receives a mapping key K
that can be used to index properties of a type. The following implements a mapped type that remaps each property to be T | null
const T = Type.Object({ // type T = {
x: Type.Number(), // x: number,
y: Type.String(), // y: string,
z: Type.Boolean() // z: boolean
}) // }
const M = Type.Mapped(Type.KeyOf(T), K => { // type M = { [K in keyof T]: T[K] | null }
return Type.Union([Type.Index(T, K), Type.Null()]) //
}) // ... evaluated as
//
// const M: TObject<{
// x: TUnion<[TNumber, TNull]>,
// y: TUnion<[TString, TNull]>,