Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@serverless-seoul/typebox

Package Overview
Dependencies
Maintainers
3
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@serverless-seoul/typebox - npm Package Compare versions

Comparing version 1.1.0 to 2.0.0

22

CHANGELOG.md

@@ -0,1 +1,23 @@

# [2.0.0](https://github.com/catchfashion/typebox/compare/v1.1.0...v2.0.0) (2021-07-06)
### Bug Fixes
* Allow intersect duplicated required ([#68](https://github.com/catchfashion/typebox/issues/68)) ([e6de056](https://github.com/catchfashion/typebox/commit/e6de056eb59372dcaf839be03bf4c318c2ed9963))
### Features
* merge upstream changes ([65eee4a](https://github.com/catchfashion/typebox/commit/65eee4a4e545a0f0457d4c9010a3f811b381cf73))
* Let Composition types to rely on variadic tuple types (#36) ([168c7ed](https://github.com/catchfashion/typebox/commit/168c7ed2f7592e5b05ac2e72c0f71290a2b0852f)), closes [#36](https://github.com/catchfashion/typebox/issues/36)
### BREAKING CHANGES
* Requires TypeScript 4
* fix: make TModifier type to non-any type
# [1.1.0](https://github.com/catchfashion/typebox/compare/v1.0.4...v1.1.0) (2020-11-04)

@@ -2,0 +24,0 @@

27

package.json
{
"name": "@serverless-seoul/typebox",
"version": "1.1.0",
"version": "2.0.0",
"description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",

@@ -30,6 +30,6 @@ "keywords": [

"scripts": {
"clean": "rm -rf dist",
"prebuild": "npm run clean",
"build": "tsc -p tsconfig.build.json",
"test": "mocha -r ts-node/register 'spec/index.ts'",
"clean": "hammer task clean",
"build": "hammer task build",
"example": "hammer task example",
"test": "hammer task spec",
"prepublishOnly": "npm run build"

@@ -41,13 +41,14 @@ },

"@semantic-release/github": "^7.1.1",
"@types/ajv": "^1.0.0",
"@types/chai": "^4.2.14",
"@types/mocha": "^8.0.3",
"@types/node": "^14.14.6",
"ajv": "^6.12.6",
"chai": "^4.1.2",
"mocha": "^8.2.1",
"@sinclair/hammer": "^0.12.1",
"@types/chai": "^4.2.16",
"@types/mocha": "^8.2.2",
"@types/node": "^14.14.37",
"ajv": "^8.1.0",
"ajv-formats": "^2.0.2",
"chai": "^4.3.4",
"mocha": "^8.3.2",
"semantic-release": "^17.2.2",
"ts-node": "^9.0.0",
"typescript": "^4.0.5"
"typescript": "^4.1.2"
}
}

@@ -7,9 +7,8 @@ <div align='center'>

[![npm version](https://badge.fury.io/js/%40sinclair%2Ftypebox.svg)](https://badge.fury.io/js/%40sinclair%2Ftypebox)
[![GitHub CI](https://github.com/sinclairzx81/typebox/workflows/GitHub%20CI/badge.svg)](https://github.com/sinclairzx81/typebox/actions)
[![npm version](https://badge.fury.io/js/%40sinclair%2Ftypebox.svg)](https://badge.fury.io/js/%40sinclair%2Ftypebox) [![GitHub CI](https://github.com/sinclairzx81/typebox/workflows/GitHub%20CI/badge.svg)](https://github.com/sinclairzx81/typebox/actions)
<img src='./doc/example.gif'></img>
</div>
<a name="Install"></a>

@@ -23,2 +22,12 @@

## Usage
```typescript
import { Static, Type } from '@sinclair/typebox'
const T = Type.String() // const T = { "type": "string" }
type T = Static<typeof T> // type T = string
```
<a name="Overview"></a>

@@ -28,7 +37,7 @@

TypeBox is a type builder library that allows developers to compose in-memory JSON Schema objects that can be statically resolved to TypeScript types. The schemas produced by TypeBox can be used directly as validation schemas or reflected upon by navigating the standard JSON Schema properties at runtime. 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 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. TypeBox allows one to create a single unified type that can be both statically checked by the TypeScript compiler and runtime asserted using standard JSON schema validation.
TypeBox does not provide any mechanism for validating JSON Schema. Please refer to libraries such as [AJV](https://www.npmjs.com/package/ajv) or similar to validate the schemas created with this library.
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](https://www.npmjs.com/package/ajv) to validate schemas built with this library.
Requires TypeScript 3.8.3 and above.
Requires TypeScript 4.0.3 and above.

@@ -42,551 +51,617 @@ License MIT

- [Types](#Types)
- [Function Types](#Contracts)
- [Functions](#Functions)
- [Generics](#Generics)
- [Modifiers](#Modifiers)
- [Options](#Options)
- [Extended Types](#Extended-Types)
- [Reference Types](#Reference-Types)
- [Strict](#Strict)
- [Interfaces](#Interfaces)
- [Validation](#Validation)
<a name="Example"></a>
## Example
The following shows the general usage.
The following demonstrates TypeBox's general usage.
```typescript
import { Type, Static } from '@sinclair/typebox'
// some type ...
//--------------------------------------------------------------------------------------------
//
// Let's say you have the following type ...
//
//--------------------------------------------------------------------------------------------
type Order = {
email: string,
address: string,
quantity: number,
option: 'pizza' | 'salad' | 'pie'
type Record = {
id: string,
name: string,
timestamp: number
}
// ... can be expressed as ...
//--------------------------------------------------------------------------------------------
//
// ... you can express this type in the following way.
//
//--------------------------------------------------------------------------------------------
const Order = Type.Object({
email: Type.String({ format: 'email' }),
address: Type.String(),
quantity: Type.Number({ minimum: 1, maximum: 99 }),
option: Type.Union([
Type.Literal('pizza'),
Type.Literal('salad'),
Type.Literal('pie')
])
})
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"
// ]
// }
// ... which can be reflected
//--------------------------------------------------------------------------------------------
//
// ... then infer back to the original static type this way.
//
//--------------------------------------------------------------------------------------------
console.log(JSON.stringify(Order, null, 2))
type Record = Static<typeof Record> // type Record = {
// id: string,
// name: string,
// timestamp: number
// }
// ... and statically resolved
//--------------------------------------------------------------------------------------------
//
// ... then use the type both as JSON schema and as a TypeScript type.
//
//--------------------------------------------------------------------------------------------
type TOrder = Static<typeof Order>
function receive(record: Record) { // ... as a type
if(JSON.validate(Record, record)) { // ... as a schema
// ok...
}
}
// .. and validated as JSON Schema
JSON.validate(Order, { // IETF | TC39 ?
email: 'dave@domain.com',
address: '...',
quantity: 99,
option: 'pie'
})
// ... and so on ...
```
<a href='Types'></a>
<a name="Types"></a>
## Types
TypeBox provides a number of functions to generate JSON Schema data types. The following tables list the functions TypeBox provides and their respective TypeScript and JSON Schema equivalents.
The following table outlines the TypeBox mappings between TypeScript and JSON schema.
### TypeBox > TypeScript
```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.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.Dict( │ type T = { │ const T = { │
│ Type.Number() │ [key: string] │ type: 'object' │
│ ) │ } : number │ additionalProperties: { │
│ │ │ 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, │ enum: [0, 1], │
│ B │ B │ type: 'number' │
│ } │ } │ } │
│ │ │ │
│ type T = Type.Enum(Foo) │ type T = Foo │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Union([ │ type T = string | number │ const T = { │
│ Type.String(), │ │ anyOf: [{ │
│ Type.Number() │ │ type: 'string' │
│ ]) │ │ }, { │
│ │ │ type: 'number' │
│ │ │ }] │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.KeyOf( │ type T = keyof { │ const T = { │
│ Type.Object({ │ x: number, │ enum: ['x', 'y'], │
│ x: Type.Number(), │ y: number │ type: 'string' │
│ y: Type.Number() │ } │ } │
│ }) │ │ │
│ ) │ │ │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.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.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'] │
│ │ │ } │
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
```
<a name="Modifiers"></a>
<table>
<thead>
<tr>
<th>Type</th>
<th>TypeBox</th>
<th>TypeScript</th>
</tr>
</thead>
<tbody>
<tr>
<td>Literal</td>
<td><code>const T = Type.Literal(123)</code></td>
<td><code>type T = 123</code></td>
</tr>
<tr>
<td>String</td>
<td><code>const T = Type.String()</code></td>
<td><code>type T = string</code></td>
</tr>
<tr>
<td>Number</td>
<td><code>const T = Type.Number()</code></td>
<td><code>type T = number</code></td>
</tr>
<tr>
<td>Integer</td>
<td><code>const T = Type.Integer()</code></td>
<td><code>type T = number</code></td>
</tr>
<tr>
<td>Boolean</td>
<td><code>const T = Type.Boolean()</code></td>
<td><code>type T = boolean</code></td>
</tr>
<tr>
<td>Object</td>
<td><code>const T = Type.Object({ name: Type.String() })</code></td>
<td><code>type T = { name: string }</code></td>
</tr>
<tr>
<td>Array</td>
<td><code>const T = Type.Array(Type.Number())</code></td>
<td><code>type T = number[]</code></td>
</tr>
<tr>
<td>Map</td>
<td><code>const T = Type.Map(Type.Number())</code></td>
<td><code>type T = { [key: string] } : number</code></td>
</tr>
<tr>
<td>Intersect</td>
<td><code>const T = Type.Intersect([Type.String(), Type.Number()])</code></td>
<td><code>type T = string & number</code></td>
</tr>
<tr>
<td>Union</td>
<td><code>const T = Type.Union([Type.String(), Type.Number()])</code></td>
<td><code>type T = string | number</code></td>
</tr>
<tr>
<td>Tuple</td>
<td><code>const T = Type.Tuple([Type.String(), Type.Number()])</code></td>
<td><code>type T = [string, number]</code></td>
</tr>
<tr>
<td>Any</td>
<td><code>const T = Type.Any()</code></td>
<td><code>type T = any</code></td>
</tr>
<tr>
<td>Null</td>
<td><code>const T = Type.Null()</code></td>
<td><code>type T = null</code></td>
</tr>
<tr>
<td>Pattern</td>
<td><code>const T = Type.Pattern(/foo/)</code></td>
<td><code>type T = string</code></td>
</tr>
<tr>
<td>Guid</td>
<td><code>const T = Type.Guid()</code></td>
<td><code>type T = string</code></td>
</tr>
</tbody>
</table>
### Modifiers
### TypeBox > JSON Schema
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.
<table>
<thead>
<tr>
<th>Type</th>
<th>TypeBox</th>
<th>JSON Schema</th>
</tr>
</thead>
<tbody>
<tr>
<td>Literal</td>
<td><code>const T = Type.Literal(123)</code></td>
<td><code>{ type: 'number', enum: [123] }</code></td>
</tr>
<tr>
<td>String</td>
<td><code>const T = Type.String()</code></td>
<td><code>{ type: 'string' }</code></td>
</tr>
<tr>
<td>Number</td>
<td><code>const T = Type.Number()</code></td>
<td><code>{ type: 'number' }</code></td>
</tr>
<tr>
<td>Integer</td>
<td><code>const T = Type.Number()</code></td>
<td><code>{ type: 'integer' }</code></td>
</tr>
<tr>
<td>Boolean</td>
<td><code>const T = Type.Boolean()</code></td>
<td><code>{ type: 'boolean' }</code></td>
</tr>
<tr>
<td>Object</td>
<td><code>const T = Type.Object({ name: Type: String() })</code></td>
<td><code>{ type: 'object': properties: { name: { type: 'string' } }, required: ['name'] }</code></td>
</tr>
<tr>
<td>Array</td>
<td><code>const T = Type.Array(Type.String())</code></td>
<td><code>{ type: 'array': items: { type: 'string' } }</code></td>
</tr>
<tr>
<td>Map</td>
<td><code>const T = Type.Map(Type.Number())</code></td>
<td><code>{ type: 'object', additionalProperties: { type: 'number' } }</code></td>
</tr>
<tr>
<td>Intersect</td>
<td><code>const T = Type.Intersect([Type.Number(), Type.String()])</code></td>
<td><code>{ allOf: [{ type: 'number'}, {type: 'string'}] }</code></td>
</tr>
<tr>
<td>Union</td>
<td><code>const T = Type.Union([Type.Number(), Type.String()])</code></td>
<td><code>{ oneOf: [{ type: 'number'}, {type: 'string'}] }</code></td>
</tr>
<tr>
<td>Tuple</td>
<td><code>const T = Type.Tuple([Type.Number(), Type.String()])</code></td>
<td><code>{ type: "array", items: [{type: 'string'}, {type: 'number'}], additionalItems: false, minItems: 2, maxItems: 2 }</code></td>
</tr>
<tr>
<td>Any</td>
<td><code>const T = Type.Any()</code></td>
<td><code>{ }</code></td>
</tr>
<tr>
<td>Null</td>
<td><code>const T = Type.Null()</code></td>
<td><code>{ type: 'null' }</code></td>
</tr>
<tr>
<td>Pattern</td>
<td><code>const T = Type.Pattern(/foo/)</code></td>
<td><code>{ type: 'string', pattern: 'foo' }</code></td>
</tr>
<tr>
<td>Guid</td>
<td><code>const T = Type.Guid()</code></td>
<td><code>{ type: 'string', pattern: '&lt;guid-regex&gt;' }</code></td>
</tr>
</tbody>
</table>
```typescript
┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
│ 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' │
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
```
### Type Modifiers
<a name="Options"></a>
The following are object property modifiers. Note that `Type.Optional(...)` will make the schema object property optional. `Type.Readonly(...)` however has no effect on the underlying schema as is only meaningful to TypeScript.
### Options
<table>
<thead>
<tr>
<th>Type</th>
<th>TypeBox</th>
<th>TypeScript</th>
</tr>
</thead>
<tbody>
<tr>
<td>Readonly</td>
<td><code>const T = Type.Object({ email: Type.Readonly(Type.String()) })</code></td>
<td><code>type T = { readonly email: string }</code></td>
</tr>
<tr>
<td>Optional</td>
<td><code>const T = Type.Object({ email: Type.Optional(Type.String()) })</code></td>
<td><code>type T = { email?: string }</code></td>
</tr>
</tbody>
</table>
You can pass additional JSON schema properties on the last argument of any given type. The following are some examples.
### Enums
```typescript
// string must be an email
const T = Type.String({ format: 'email' })
It is possible to define TypeScript enums and use them as part of your TypeBox schema.
Both number and string-valued enums are supported.
// number must be a multiple of 2
const T = Type.Number({ multipleOf: 2 })
```ts
enum Color {
Red = 'red',
Blue = 'blue'
}
const T = Type.Enum(Color); // -> json-schema: `{ enum: ['red','green'] }`
// array must have at least 5 integer values
const T = Type.Array(Type.Integer(), { minItems: 5 })
```
Note that the generated json-schema will only permit the *values* of the enum, not its *keys*.
In TypeScript, if you omit the *value* for an enum option, TypeScript will implicitly assign the option a numeric value.
E.g.:
```ts
enum Color {
Red, // implicitly gets value `0`
Blue // implicitly gets value `1`
}
<a name="Extended-Types"></a>
const T = Type.Enum(Color); // -> json-schema: `{ enum: [0, 1] }`
```
### Extended Types
### User Defined Schema Properties
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.
It's possible to specify custom properties on schemas. The last parameter on each TypeBox function accepts an optional `UserDefinedOptions` object. Properties specified in this object will appear as properties on the resulting schema object. Consider the following.
```typescript
const T = Type.Object({
value: Type.String({
description: 'A required string.'
})
}, {
description: 'An object with a value'
})
┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
│ TypeBox │ TypeScript │ Extended Schema │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Constructor([ │ type T = new ( │ const T = { │
| Type.String(), │ arg0: string, │ type: 'constructor' │
│ Type.Number(), │ arg1: number │ arguments: [{ │
│ ], Type.Boolean()) │ ) => boolean │ type: 'string' │
│ │ │ }, { │
│ │ │ type: 'number' │
│ │ │ }], │
│ │ │ returns: { │
│ │ │ type: 'boolean' │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Function([ │ type T = ( │ const T = { │
| Type.String(), │ arg0: string, │ type : 'function', │
│ Type.Number(), │ arg1: number │ arguments: [{ │
│ ], Type.Boolean()) │ ) => boolean │ type: 'string' │
│ │ │ }, { │
│ │ │ type: 'number' │
│ │ │ }], │
│ │ │ returns: { │
│ │ │ type: 'boolean' │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Promise( │ type T = Promise<string> │ const T = { │
| Type.String() │ │ type: 'promise', │
| ) │ │ item: { │
│ │ │ type: 'string' │
│ │ │ } │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Undefined() │ type T = undefined │ const T = { │
| │ │ type: 'undefined' │
| │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
│ const T = Type.Void() │ type T = void │ const T = { │
| │ │ type: 'void' │
| │ │ } │
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
```
```json
{
"description": "An object with a value",
"type": "object",
"properties": {
"value": {
"description": "A required string.",
"type": "string"
}
},
"required": [
"value"
]
}
```
<a name="Contracts"></a>
<a name="Reference-Types"></a>
## Function Types
### Reference Types
TypeBox allows function signatures to be composed in a similar way to other types, but uses a custom schema format to achieve this. Note, this format is not JSON Schema, rather it embeds JSON Schema to encode function `arguments` and `return` types. The format also provides additional types not present in JSON Schema; `Type.Constructor()`, `Type.Void()`, `Type.Undefined()`, and `Type.Promise()`.
Type referencing can be useful to help reduce schema duplication when composing complex schemas. TypeBox allows for type referencing with the `Type.Box(...)` and `Type.Ref(...)` functions. The `Type.Box(...)` function creates a container for set of common related types and the `Type.Ref(...)` function allows referencing into the box. The following shows a set of common math types contained within a box, and a vertex structure that references those types.
For more information on using functions, see the [Functions](#Functions) and [Generics](#Generics) sections below.
### Format
The following is an example of how TypeBox encodes function signatures.
```typescript
type T = (a: string, b: number) => boolean
{
"type": "function",
"returns": { "type": "boolean" },
"arguments": [
{"type": "string" },
{"type": "number" },
]
}
const Math3D = Type.Box('math3d', { // const Math3D = {
Vector4: Type.Object({ // $id: 'math3d',
x: Type.Number(), // definitions: {
y: Type.Number(), // Vector4: {
z: Type.Number(), // type: 'object',
w: Type.Number() // properties: {
}), // x: { type: 'number' },
Vector3: Type.Object({ // y: { type: 'number' },
x: Type.Number(), // z: { type: 'number' },
y: Type.Number(), // w: { type: 'number' }
z: Type.Number() // },
}), // required: ['x', 'y', 'z', 'w']
Vector2: Type.Object({ // },
x: Type.Number(), // Vector3: {
y: Type.Number() // type: 'object',
}) // properties: {
}) // x: { 'type': 'number' },
// y: { 'type': 'number' },
// z: { 'type': 'number' }
// },
// required: ['x', 'y', 'z']
// },
// Vector2: {
// type: 'object',
// properties: {
// x: { 'type': 'number' },
// y: { 'type': 'number' },
// },
// required: ['x', 'y']
// }
// }
// }
const Vertex = Type.Object({ // const Vertex = {
position: Type.Ref(Math3D, 'Vector4'), // type: 'object',
normal: Type.Ref(Math3D, 'Vector3'), // properties: {
uv: Type.Ref(Math3D, 'Vector2') // position: { $ref: 'math3d#/definitions/Vector4' },
}) // normal: { $ref: 'math3d#/definitions/Vector3' },
// uv: { $ref: 'math3d#/definitions/Vector2' }
// },
// required: ['position', 'normal', 'uv']
// }
```
### TypeBox > TypeScript
<a name="Strict"></a>
<table>
<thead>
<tr>
<th>Intrinsic</th>
<th>TypeBox</th>
<th>TypeScript</th>
</tr>
</thead>
<tbody>
<tr>
<td>Function</td>
<td><code>const T = Type.Function([Type.String()], Type.String())</code></td>
<td><code>type T = (arg0: string) => string</code></td>
</tr>
<tr>
<td>Constructor</td>
<td><code>const T = Type.Constructor([Type.String()], Type.String())</code></td>
<td><code>type T = new (arg0: string) => string</code></td>
</tr>
<tr>
<td>Promise</td>
<td><code>const T = Type.Promise(Type.String())</code></td>
<td><code>type T = Promise&lt;string&gt;</code></td>
</tr>
<tr>
<td>Undefined</td>
<td><code>const T = Type.Undefined()</code></td>
<td><code>type T = undefined</code></td>
</tr>
<tr>
<td>Void</td>
<td><code>const T = Type.Void()</code></td>
<td><code>type T = void</code></td>
</tr>
</tbody>
</table>
### Strict
### TypeBox > JSON Function
TypeBox includes the properties `kind` and `modifier` on each underlying schema. These properties are used to help TypeBox statically resolve the schemas to the appropriate TypeScript type as well as apply the appropriate modifiers to an objects properties (such as optional). 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 nessasary.
<table>
<thead>
<tr>
<th>Intrinsic</th>
<th>TypeBox</th>
<th>JSON Function</th>
</tr>
</thead>
<tbody>
<tr>
<td>Function</td>
<td><code>const T = Type.Function([Type.String()], Type.Number())</code></td>
<td><code>{ type: 'function', arguments: [ { type: 'string' } ], returns: { type: 'number' } }</code></td>
</tr>
<tr>
<td>Constructor</td>
<td><code>const T = Type.Constructor([Type.String()], Type.Number())</code></td>
<td><code>{ type: 'constructor', arguments: [ { type: 'string' } ], returns: { type: 'number' } }</code></td>
</tr>
<tr>
<td>Promise</td>
<td><code>const T = Type.Promise(Type.String())</code></td>
<td><code>{ type: 'promise', item: { type: 'string' } }</code></td>
</tr>
<tr>
<td>Undefined</td>
<td><code>const T = Type.Undefined()</code></td>
<td><code>{ type: 'undefined' }</code></td>
</tr>
<tr>
<td>Void</td>
<td><code>const T = Type.Void()</code></td>
<td><code>{ type: 'void' }</code></td>
</tr>
</tbody>
</table>
```typescript
const T = Type.Object({ // const T = {
name: Type.Optional(Type.String()) // kind: Symbol(ObjectKind),
}) // type: 'object',
// properties: {
// name: {
// kind: Symbol(StringKind),
// type: 'string',
// modifier: Symbol(OptionalModifier)
// }
// }
// }
<a href='Functions'></a>
const U = Type.Strict(T) // const U = {
// type: 'object',
// properties: {
// name: {
// type: 'string'
// }
// }
// }
```
## Functions
<a name="Interfaces"></a>
The following demonstrates creating function signatures for the following TypeScript types.
### Interfaces
### TypeScript
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 is how one might approach this in TypeScript.
```typescript
type T0 = (a0: number, a1: string) => boolean;
interface CreateRecordRequest {
data: string
}
type T1 = (a0: string, a1: () => string) => void;
interface CreateRecordResponse {
id: string
}
type T2 = (a0: string) => Promise<number>;
interface ControllerInterface {
createRecord(record: CreateRecordRequest): Promise<CreateRecordResponse>
}
type T3 = () => () => string;
type T4 = new () => string
class Controller implements ControllerInterface {
async createRecord(record: CreateRecordRequest): Promise<CreateRecordResponse> {
return { id: '1' }
}
}
```
### TypeBox
The following is the TypeBox equivalent.
```typescript
const T0 = Type.Function([Type.Number(), Type.String()], Type.Boolean())
import { Type, Static } from '@sinclair/typebox'
const T1 = Type.Function([Type.String(), Type.Function([], Type.String())], Type.Void())
type CreateRecordRequest = Static<typeof CreateRecordRequest>
const CreateRecordRequest = Type.Object({
data: Type.String()
})
type CreateRecordResponse = Static<typeof CreateRecordResponse>
const CreateRecordResponse = Type.Object({
id: Type.String()
})
const T2 = Type.Function([Type.String()], Type.Promise(Type.Number()))
type ControllerInterface = Static<typeof ControllerInterface>
const ControllerInterface = Type.Object({
createRecord: Type.Function([CreateRecordRequest], Type.Promise(CreateRecordResponse))
})
const T3 = Type.Function([], Type.Function([], Type.String()))
const T4 = Type.Constructor([], Type.String())
class Controller implements ControllerInterface {
async createRecord(record: CreateRecordRequest): Promise<CreateRecordResponse> {
return { id: '1' }
}
}
```
<a name="Generics"></a>
## Generics
Generic function signatures can be composed with TypeScript functions with [Generic Constraints](https://www.typescriptlang.org/docs/handbook/generics.html#generic-constraints).
### TypeScript
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.
```typescript
type ToString = <T>(t: T) => string
```
### TypeBox
```typescript
import { Type, Static, TStatic } from '@sinclair/typebox'
const ToString = <G extends TStatic>(T: G) => Type.Function([T], Type.String())
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"
// ]
// }
```
However, it's not possible to statically infer what type `ToString` is without first creating some specialized variant of it. The following creates a specialization called `NumberToString`.
```typescript
const NumberToString = ToString(Type.Number())
type X = Static<typeof NumberToString>
<a name="Validation"></a>
// X is (arg0: number) => string
```
To take things a bit further, the following code contains some generic TypeScript REST setup with controllers that take some generic resource of type `T`. Below this we express that same setup using TypeBox. The resulting type `IRecordController` contains reflectable interface metadata about the `RecordController`.
### TypeScript
```typescript
interface IController<T> {
get (): Promise<T>
post (resource: T): Promise<void>
put (resource: T): Promise<void>
delete (resource: T): Promise<void>
}
### Validation
interface Record {
key: string
value: string
}
TypeBox does not provide JSON schema validation out of the box and expects users to select an appropriate JSON schema validation library for their needs. TypeBox schemas should match JSON Schema draft 6 so any library capable of draft 6 should be fine. A good library to use for validation is [Ajv](https://www.npmjs.com/package/ajv). The following example shows setting up Ajv 7 to work with TypeBox.
class RecordController implements IController<Record> {
async get (): Promise<Record> { throw 'not implemented' }
async post (resource: Record): Promise<void> { /* */ }
async put (resource: Record): Promise<void> { /* */ }
async delete(resource: Record): Promise<void> { /* */ }
}
```bash
$ npm install ajv ajv-formats --save
```
### TypeBox
```typescript
import { Type, Static, TStatic } from '@sinclair/typebox'
import { Type } from '@sinclair/typebox'
import addFormats from 'ajv-formats'
import Ajv from 'ajv'
const IController = <G extends TStatic>(T: G) => Type.Object({
get: Type.Function([], Type.Promise(T)),
post: Type.Function([T], Type.Promise(Type.Void())),
put: Type.Function([T], Type.Promise(Type.Void())),
delete: Type.Function([T], Type.Promise(Type.Void())),
// Setup
const ajv = addFormats(new Ajv(), [
'date-time',
'time',
'date',
'email',
'hostname',
'ipv4',
'ipv6',
'uri',
'uri-reference',
'uuid',
'uri-template',
'json-pointer',
'relative-json-pointer',
'regex'
]).addKeyword('kind')
.addKeyword('modifier')
// TypeBox
const User = Type.Object({
name: Type.String(),
email: Type.String({ format: 'email' })
})
type Record = Static<typeof Record>
const Record = Type.Object({
key: Type.String(),
value: Type.String()
// Validate
const isValid = ajv.validate(User, {
name: 'dave',
email: 'dave@domain.com'
})
type IRecordController = Static<typeof IRecordController>
const IRecordController = IController(Record)
class RecordController implements IRecordController {
async get (): Promise<Record> { throw 'not implemented' }
async post (resource: Record): Promise<void> { /* */ }
async put (resource: Record): Promise<void> { /* */ }
async delete(resource: Record): Promise<void> { /* */ }
}
// Reflect
console.log(IRecordController)
//
// isValid -> true
//
```
<a href='Validation'></a>
## Validation
The following uses the library [Ajv](https://www.npmjs.com/package/ajv) to validate a type.
```typescript
import * Ajv from 'ajv'
const ajv = new Ajv({ })
ajv.validate(Type.String(), 'hello') // true
ajv.validate(Type.String(), 123) // false
```

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc