@sinclair/typebox

Json Schema Type Builder with Static Type Resolution for TypeScript

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
@sinclair/typebox
4,23740.32.2320 hours ago4 years agoMinified + gzip package size for @sinclair/typebox in KB

Readme

TypeBox

Json Schema Type Builder with Static Type Resolution for TypeScript



npm version Downloads Build License

Install

```bash $ npm install @sinclair/typebox --save ```

Example

```typescript 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 // 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 with the same flexibility as TypeScript's programmable 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

- Json - JavaScript - Import - Options - Properties - Generics - References - Recursive - Template Literal - Indexed - Mapped - Conditional - Intrinsic - Transform - Rest - Guard - Unsafe - Strict - Create - Clone - Check - Convert - Default - Clean - Cast - Decode - Encode - Equal - Hash - Diff - Patch - Errors - Mutate - Pointer - Type - Format - Ajv - TypeCompiler - Policies - Compile - Validate - Compression

Usage

The following shows general usage. ```typescript 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 // type T = {
//   id: string,
//   name: string,
//   timestamp: number
// }
//-------------------------------------------------------------------------------------------- // // ... then use the type both as Json Schema and as a TypeScript type. // //-------------------------------------------------------------------------------------------- import { Value } from '@sinclair/typebox/value' function receive(value: T) { // ... as a Static Type if(Value.Check(T, value)) { // ... as a Json Schema
// ok...
} } ```

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. ```typescript ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐ │ 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 T = Type.Object({ │ type T = { │ const R = { │ │ x: Type.Number(), │ x: number, │ $ref: 'T' │ │ y: Type.Number() │ y: number │ } │ │ }, { $id: 'T' }) | } │ │ │ │ │ │ │ const R = Type.Ref(T) │ type R = 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. ```typescript ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐ │ 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 │ 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 │ 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. ```typescript import { Type, type Static } from '@sinclair/typebox' ``` You can also selectively import types. This enables modern bundlers to tree shake for unused types. ```typescript 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. ```typescript // 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. ```typescript ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐ │ 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. ```typescript import { Type, type Static, type TSchema } from '@sinclair/typebox' const Vector = (T: T) => Type.Object({ // type Vector = {
x: T,                                            //   x: T,
y: T,                                            //   y: T,
z: T                                             //   z: T
}) // } const NumberVector = Vector(Type.Number()) // type NumberVector = Vector ``` Generic types are often used to create aliases for complex types. The following creates a Nullable generic type. ```typescript const Nullable = (schema: T) => Type.Union(schema, Type.Null()) const T = Nullable(Type.String()) // const T = {
//   anyOf: [
//     { type: 'string' },
//     { type: 'null' }
//   ]
// }
type T = Static // type T = string | null ```

Reference Types

Reference types can be created with Ref. These types infer the same as the target type but only store a named $ref to the target type. ```typescript const Vector = Type.Object({ // const Vector = { x: Type.Number(), // type: 'object', y: Type.Number(), // required: 'x', 'y', 'z', }, { $id: 'Vector' }) // properties: {
//     x: { type: 'number' },
//     y: { type: 'number' }
//   },
//   $id: 'Vector'
// }
const VectorRef = Type.Ref(Vector) // const VectorRef = {
//   $ref: 'Vector'
// }
type VectorRef = Static // type VectorRef = {
//    x: number,
//    y: number
// }
``` Use Deref to dereference a type. This function will replace any interior reference with the target type. ```typescript const Vertex = Type.Object({ // const Vertex = { position: VectorRef, // type: 'object', texcoord: VectorRef, // required: 'position', 'texcoord', }) // properties: {
//     position: { $ref: 'Vector' },
//     texcoord: { $ref: 'Vector' }
//   }
// }
const VertexDeref = Type.Deref(Vertex, Vector) // const VertexDeref = {
//   type: 'object',
//   required: ['position', 'texcoord'],
//   properties: {
//     position: {
//       type: 'object',
//       required: ['x', 'y', 'z'],
//       properties: {
//         x: { type: 'number' },
//         y: { type: 'number' }
//       }
//     },
//     texcoord: {
//       type: 'object',
//       required: ['x', 'y', 'z'],
//       properties: {
//         x: { type: 'number' },
//         y: { type: 'number' }
//       }
//     }
//   }
// }
``` Note that Ref types do not store structural information about the type they're referencing. Because of this, these types cannot be used with some mapping types (such as Partial or Pick). For applications that require mapping on Ref, use Deref to normalize the type first.

Recursive Types

TypeBox supports recursive data structures with Recursive. This type wraps an interior type and provides it a this context that allows the type to reference itself. The following creates a recursive type. Singular recursive inference is also supported. ```typescript const Node = Type.Recursive(This => Type.Object({ // const Node = { id: Type.String(), // $id: 'Node', nodes: Type.Array(This) // type: 'object', }), { $id: 'Node' }) // properties: {
//     id: {
//       type: 'string'
//     },
//     nodes: {
//       type: 'array',
//       items: {
//         $ref: 'Node'
//       }
//     }
//   },
//   required: [
//     'id',
//     'nodes'
//   ]
// }
type Node = Static // type Node = {
//   id: string
//   nodes: Node[]
// }
function test(node: Node) { const id = node.nodes0.nodes0.id // id is 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 // TypeScript type K = prop${'A'|'B'|'C'} // type T = 'propA' | 'propB' | 'propC' type R = Record // type R = {
//   propA: string
//   propB: string
//   propC: string
// }
// TypeBox const K = Type.TemplateLiteral('prop${A|B|C}') // const K: TTemplateLiteral<
//   TLiteral<'prop'>,