@sinclair/typebox 0.24.50 → 0.24.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/compiler/compiler.d.ts +25 -28
  2. package/compiler/compiler.js +408 -409
  3. package/compiler/index.d.ts +2 -2
  4. package/compiler/index.js +47 -47
  5. package/conditional/conditional.d.ts +17 -17
  6. package/conditional/conditional.js +91 -91
  7. package/conditional/index.d.ts +2 -2
  8. package/conditional/index.js +45 -45
  9. package/conditional/structural.d.ts +11 -11
  10. package/conditional/structural.js +657 -657
  11. package/errors/errors.d.ts +60 -60
  12. package/errors/errors.js +398 -398
  13. package/errors/index.d.ts +1 -1
  14. package/errors/index.js +44 -44
  15. package/format/format.d.ts +12 -12
  16. package/format/format.js +55 -55
  17. package/format/index.d.ts +1 -1
  18. package/format/index.js +44 -44
  19. package/guard/guard.d.ts +56 -56
  20. package/guard/guard.js +351 -351
  21. package/guard/index.d.ts +1 -1
  22. package/guard/index.js +44 -44
  23. package/license +22 -22
  24. package/package.json +43 -40
  25. package/readme.md +1152 -1152
  26. package/typebox.d.ts +408 -408
  27. package/typebox.js +383 -383
  28. package/value/cast.d.ts +26 -26
  29. package/value/cast.js +364 -364
  30. package/value/check.d.ts +8 -8
  31. package/value/check.js +331 -331
  32. package/value/clone.d.ts +3 -3
  33. package/value/clone.js +65 -65
  34. package/value/create.d.ts +14 -14
  35. package/value/create.js +357 -357
  36. package/value/delta.d.ts +22 -22
  37. package/value/delta.js +168 -168
  38. package/value/equal.d.ts +3 -3
  39. package/value/equal.js +74 -74
  40. package/value/index.d.ts +3 -3
  41. package/value/index.js +48 -48
  42. package/value/is.d.ts +10 -10
  43. package/value/is.js +49 -49
  44. package/value/pointer.d.ts +24 -24
  45. package/value/pointer.js +142 -142
  46. package/value/value.d.ts +31 -31
  47. package/value/value.js +81 -81
package/readme.md CHANGED
@@ -1,1152 +1,1152 @@
1
- <div align='center'>
2
-
3
- <h1>TypeBox</h1>
4
-
5
- <p>JSON Schema Type Builder with Static Type Resolution for TypeScript</p>
6
-
7
- <img src="https://github.com/sinclairzx81/typebox/blob/master/typebox.png?raw=true" />
8
-
9
- <br />
10
- <br />
11
-
12
- [![npm version](https://badge.fury.io/js/%40sinclair%2Ftypebox.svg)](https://badge.fury.io/js/%40sinclair%2Ftypebox)
13
- [![Downloads](https://img.shields.io/npm/dm/%40sinclair%2Ftypebox.svg)](https://www.npmjs.com/package/%40sinclair%2Ftypebox)
14
- [![GitHub CI](https://github.com/sinclairzx81/typebox/workflows/GitHub%20CI/badge.svg)](https://github.com/sinclairzx81/typebox/actions)
15
-
16
- </div>
17
-
18
- <a name="Install"></a>
19
-
20
- ## Install
21
-
22
- Node
23
-
24
- ```bash
25
- $ npm install @sinclair/typebox --save
26
- ```
27
-
28
- Deno and ESM
29
-
30
- ```typescript
31
- import { Static, Type } from 'https://esm.sh/@sinclair/typebox'
32
- ```
33
-
34
- ## Example
35
-
36
- ```typescript
37
- import { Static, Type } from '@sinclair/typebox'
38
-
39
- const T = Type.String() // const T = { type: 'string' }
40
-
41
- type T = Static<typeof T> // type T = string
42
- ```
43
-
44
- <a name="Overview"></a>
45
-
46
- ## Overview
47
-
48
- 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.
49
-
50
- TypeBox 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.
51
-
52
- License MIT
53
-
54
- ## Contents
55
- - [Install](#install)
56
- - [Overview](#overview)
57
- - [Usage](#usage)
58
- - [Types](#types)
59
- - [Standard](#types-standard)
60
- - [Modifiers](#types-modifiers)
61
- - [Options](#types-options)
62
- - [Extended](#types-extended)
63
- - [Reference](#types-reference)
64
- - [Recursive](#types-recursive)
65
- - [Generic](#types-generic)
66
- - [Conditional](#types-conditional)
67
- - [Unsafe](#types-unsafe)
68
- - [Guards](#types-guards)
69
- - [Strict](#types-strict)
70
- - [Values](#values)
71
- - [Create](#values-create)
72
- - [Clone](#values-clone)
73
- - [Check](#values-check)
74
- - [Cast](#values-cast)
75
- - [Equal](#values-equal)
76
- - [Diff](#values-diff)
77
- - [Patch](#values-patch)
78
- - [Errors](#values-errors)
79
- - [Pointer](#values-pointer)
80
- - [TypeCheck](#typecheck)
81
- - [Ajv](#typecheck-ajv)
82
- - [Compiler](#typecheck-compiler)
83
- - [Formats](#typecheck-formats)
84
- - [Benchmark](#benchmark)
85
- - [Compile](#benchmark-compile)
86
- - [Validate](#benchmark-validate)
87
- - [Compression](#benchmark-compression)
88
- - [Contribute](#contribute)
89
-
90
- <a name="Example"></a>
91
-
92
- ## Usage
93
-
94
- The following demonstrates TypeBox's general usage.
95
-
96
- ```typescript
97
-
98
- import { Static, Type } from '@sinclair/typebox'
99
-
100
- //--------------------------------------------------------------------------------------------
101
- //
102
- // Let's say you have the following type ...
103
- //
104
- //--------------------------------------------------------------------------------------------
105
-
106
- type T = {
107
- id: string,
108
- name: string,
109
- timestamp: number
110
- }
111
-
112
- //--------------------------------------------------------------------------------------------
113
- //
114
- // ... you can express this type in the following way.
115
- //
116
- //--------------------------------------------------------------------------------------------
117
-
118
- const T = Type.Object({ // const T = {
119
- id: Type.String(), // type: 'object',
120
- name: Type.String(), // properties: {
121
- timestamp: Type.Integer() // id: {
122
- }) // type: 'string'
123
- // },
124
- // name: {
125
- // type: 'string'
126
- // },
127
- // timestamp: {
128
- // type: 'integer'
129
- // }
130
- // },
131
- // required: [
132
- // 'id',
133
- // 'name',
134
- // 'timestamp'
135
- // ]
136
- // }
137
-
138
- //--------------------------------------------------------------------------------------------
139
- //
140
- // ... then infer back to the original static type this way.
141
- //
142
- //--------------------------------------------------------------------------------------------
143
-
144
- type T = Static<typeof T> // type T = {
145
- // id: string,
146
- // name: string,
147
- // timestamp: number
148
- // }
149
-
150
- //--------------------------------------------------------------------------------------------
151
- //
152
- // ... then use the type both as JSON schema and as a TypeScript type.
153
- //
154
- //--------------------------------------------------------------------------------------------
155
-
156
- function receive(value: T) { // ... as a Type
157
-
158
- if(JSON.validate(T, value)) { // ... as a Schema
159
-
160
- // ok...
161
- }
162
- }
163
- ```
164
-
165
- <a name='types'></a>
166
-
167
- ## Types
168
-
169
- 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.
170
-
171
- <a name='types-standard'></a>
172
-
173
- ### Standard
174
-
175
- The following table lists the standard TypeBox types.
176
-
177
- ```typescript
178
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
179
- │ TypeBox │ TypeScript │ JSON Schema │
180
- │ │ │ │
181
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
182
- │ const T = Type.Any() │ type T = any │ const T = { } │
183
- │ │ │ │
184
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
185
- │ const T = Type.Unknown() │ type T = unknown │ const T = { } │
186
- │ │ │ │
187
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
188
- │ const T = Type.String() │ type T = string │ const T = { │
189
- │ │ │ type: 'string' │
190
- │ │ │ } │
191
- │ │ │ │
192
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
193
- │ const T = Type.Number() │ type T = number │ const T = { │
194
- │ │ │ type: 'number' │
195
- │ │ │ } │
196
- │ │ │ │
197
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
198
- │ const T = Type.Integer() │ type T = number │ const T = { │
199
- │ │ │ type: 'integer' │
200
- │ │ │ } │
201
- │ │ │ │
202
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
203
- │ const T = Type.Boolean() │ type T = boolean │ const T = { │
204
- │ │ │ type: 'boolean' │
205
- │ │ │ } │
206
- │ │ │ │
207
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
208
- │ const T = Type.Null() │ type T = null │ const T = { │
209
- │ │ │ type: 'null' │
210
- │ │ │ } │
211
- │ │ │ │
212
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
213
- │ const T = Type.RegEx(/foo/) │ type T = string │ const T = { │
214
- │ │ │ type: 'string', │
215
- │ │ │ pattern: 'foo' │
216
- │ │ │ } │
217
- │ │ │ │
218
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
219
- │ const T = Type.Literal(42) │ type T = 42 │ const T = { │
220
- │ │ │ const: 42, │
221
- │ │ │ type: 'number' │
222
- │ │ │ } │
223
- │ │ │ │
224
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
225
- │ const T = Type.Array( │ type T = number[] │ const T = { │
226
- │ Type.Number() │ │ type: 'array', │
227
- │ ) │ │ items: { │
228
- │ │ │ type: 'number' │
229
- │ │ │ } │
230
- │ │ │ } │
231
- │ │ │ │
232
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
233
- │ const T = Type.Object({ │ type T = { │ const T = { │
234
- │ x: Type.Number(), │ x: number, │ type: 'object', │
235
- │ y: Type.Number() │ y: number │ properties: { │
236
- │ }) │ } │ x: { │
237
- │ │ │ type: 'number' │
238
- │ │ │ }, │
239
- │ │ │ y: { │
240
- │ │ │ type: 'number' │
241
- │ │ │ } │
242
- │ │ │ }, │
243
- │ │ │ required: ['x', 'y'] │
244
- │ │ │ } │
245
- │ │ │ │
246
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
247
- │ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │
248
- │ Type.Number(), │ │ type: 'array', │
249
- │ Type.Number() │ │ items: [{ │
250
- │ ]) │ │ type: 'number' │
251
- │ │ │ }, { │
252
- │ │ │ type: 'number' │
253
- │ │ │ }], │
254
- │ │ │ additionalItems: false, │
255
- │ │ │ minItems: 2, │
256
- │ │ │ maxItems: 2 │
257
- │ │ │ } │
258
- │ │ │ │
259
- │ │ │ │
260
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
261
- │ enum Foo { │ enum Foo { │ const T = { │
262
- │ A, │ A, │ anyOf: [{ │
263
- │ B │ B │ type: 'number', │
264
- │ } │ } │ const: 0 │
265
- │ │ │ }, { │
266
- │ const T = Type.Enum(Foo) │ type T = Foo │ type: 'number', │
267
- │ │ │ const: 1 │
268
- │ │ │ }] │
269
- │ │ │ } │
270
- │ │ │ │
271
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
272
- │ const T = Type.KeyOf( │ type T = keyof { │ const T = { │
273
- │ Type.Object({ │ x: number, │ anyOf: [{ │
274
- │ x: Type.Number(), │ y: number │ type: 'string', │
275
- │ y: Type.Number() │ } │ const: 'x' │
276
- │ }) │ │ }, { │
277
- │ ) │ │ type: 'string', │
278
- │ │ │ const: 'y' │
279
- │ │ │ }] │
280
- │ │ │ } │
281
- │ │ │ │
282
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
283
- │ const T = Type.Union([ │ type T = string | number │ const T = { │
284
- │ Type.String(), │ │ anyOf: [{ │
285
- │ Type.Number() │ │ type: 'string' │
286
- │ ]) │ │ }, { │
287
- │ │ │ type: 'number' │
288
- │ │ │ }] │
289
- │ │ │ } │
290
- │ │ │ │
291
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
292
- │ const T = Type.Intersect([ │ type T = { │ const T = { │
293
- │ Type.Object({ │ x: number │ type: 'object', │
294
- │ x: Type.Number() │ } & { │ properties: { │
295
- │ }), │ y: number │ x: { │
296
- │ Type.Object({ │ } │ type: 'number' │
297
- │ y: Type.Number() │ │ }, │
298
- │ }) │ │ y: { │
299
- │ ]) │ │ type: 'number' │
300
- │ │ │ } │
301
- │ │ │ }, │
302
- │ │ │ required: ['x', 'y'] │
303
- │ │ │ } │
304
- │ │ │ │
305
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
306
- │ const T = Type.Never() │ type T = never │ const T = { │
307
- │ │ │ allOf: [{ │
308
- │ │ │ type: 'boolean', │
309
- │ │ │ const: false │
310
- │ │ │ }, { │
311
- │ │ │ type: 'boolean', │
312
- │ │ │ const: true │
313
- │ │ │ }] │
314
- │ │ │ } │
315
- │ │ │ │
316
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
317
- │ const T = Type.Record( │ type T = Record< │ const T = { │
318
- │ Type.String(), │ string, │ type: 'object', │
319
- │ Type.Number() │ number, │ patternProperties: { │
320
- │ ) │ > │ '^.*$': { │
321
- │ │ │ type: 'number' │
322
- │ │ │ } │
323
- │ │ │ } │
324
- │ │ │ } │
325
- │ │ │ │
326
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
327
- │ const T = Type.Partial( │ type T = Partial<{ │ const T = { │
328
- │ Type.Object({ │ x: number, │ type: 'object', │
329
- │ x: Type.Number(), │ y: number │ properties: { │
330
- │ y: Type.Number() | }> │ x: { │
331
- │ }) │ │ type: 'number' │
332
- │ ) │ │ }, │
333
- │ │ │ y: { │
334
- │ │ │ type: 'number' │
335
- │ │ │ } │
336
- │ │ │ } │
337
- │ │ │ } │
338
- │ │ │ │
339
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
340
- │ const T = Type.Required( │ type T = Required<{ │ const T = { │
341
- │ Type.Object({ │ x?: number, │ type: 'object', │
342
- │ x: Type.Optional( │ y?: number │ properties: { │
343
- │ Type.Number() | }> │ x: { │
344
- │ ), │ │ type: 'number' │
345
- │ y: Type.Optional( │ │ }, │
346
- │ Type.Number() │ │ y: { │
347
- │ ) │ │ type: 'number' │
348
- │ }) │ │ } │
349
- │ ) │ │ }, │
350
- │ │ │ required: ['x', 'y'] │
351
- │ │ │ } │
352
- │ │ │ │
353
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
354
- │ const T = Type.Pick( │ type T = Pick<{ │ const T = { │
355
- │ Type.Object({ │ x: number, │ type: 'object', │
356
- │ x: Type.Number(), │ y: number │ properties: { │
357
- │ y: Type.Number() | }, 'x'> │ x: { │
358
- │ }), ['x'] │ │ type: 'number' │
359
- │ ) │ │ } │
360
- │ │ │ }, │
361
- │ │ │ required: ['x'] │
362
- │ │ │ } │
363
- │ │ │ │
364
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
365
- │ const T = Type.Omit( │ type T = Omit<{ │ const T = { │
366
- │ Type.Object({ │ x: number, │ type: 'object', │
367
- │ x: Type.Number(), │ y: number │ properties: { │
368
- │ y: Type.Number() | }, 'x'> │ y: { │
369
- │ }), ['x'] │ │ type: 'number' │
370
- │ ) │ │ } │
371
- │ │ │ }, │
372
- │ │ │ required: ['y'] │
373
- │ │ │ } │
374
- │ │ │ │
375
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
376
- ```
377
-
378
- <a name='types-modifiers'></a>
379
-
380
- ### Modifiers
381
-
382
- 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.
383
-
384
- ```typescript
385
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
386
- │ TypeBox │ TypeScript │ JSON Schema │
387
- │ │ │ │
388
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
389
- │ const T = Type.Object({ │ type T = { │ const T = { │
390
- │ name: Type.Optional( │ name?: string │ type: 'object', │
391
- │ Type.String() │ } │ properties: { │
392
- │ ) │ │ name: { │
393
- │ }) │ │ type: 'string' │
394
- │ │ │ } │
395
- │ │ │ } │
396
- │ │ │ } │
397
- │ │ │ │
398
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
399
- │ const T = Type.Object({ │ type T = { │ const T = { │
400
- │ name: Type.Readonly( │ readonly name: string │ type: 'object', │
401
- │ Type.String() │ } │ properties: { │
402
- │ ) │ │ name: { │
403
- │ }) │ │ type: 'string' │
404
- │ │ │ } │
405
- │ │ │ }, │
406
- │ │ │ required: ['name'] │
407
- │ │ │ } │
408
- │ │ │ │
409
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
410
- │ const T = Type.Object({ │ type T = { │ const T = { │
411
- │ name: Type.ReadonlyOptional( │ readonly name?: string │ type: 'object', │
412
- │ Type.String() │ } │ properties: { │
413
- │ ) │ │ name: { │
414
- │ }) │ │ type: 'string' │
415
- │ │ │ } │
416
- │ │ │ } │
417
- │ │ │ } │
418
- │ │ │ │
419
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
420
- ```
421
-
422
- <a name='types-options'></a>
423
-
424
- ### Options
425
-
426
- You can pass additional JSON schema options on the last argument of any given type. The following are some examples.
427
-
428
- ```typescript
429
- // string must be an email
430
- const T = Type.String({ format: 'email' })
431
-
432
- // number must be a multiple of 2
433
- const T = Type.Number({ multipleOf: 2 })
434
-
435
- // array must have at least 5 integer values
436
- const T = Type.Array(Type.Integer(), { minItems: 5 })
437
- ```
438
-
439
- <a name='types-extended'></a>
440
-
441
- ### Extended
442
-
443
- In addition to JSON schema types, TypeBox provides several extended types that allow for the composition of `function` and `constructor` types. 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.
444
-
445
- ```typescript
446
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
447
- │ TypeBox │ TypeScript │ Extended Schema │
448
- │ │ │ │
449
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
450
- │ const T = Type.Constructor([ │ type T = new ( │ const T = { │
451
- │ Type.String(), │ arg0: string, │ type: 'constructor' │
452
- │ Type.Number() │ arg1: number │ parameters: [{ │
453
- │ ], Type.Boolean()) │ ) => boolean │ type: 'string' │
454
- │ │ │ }, { │
455
- │ │ │ type: 'number' │
456
- │ │ │ }], │
457
- │ │ │ return: { │
458
- │ │ │ type: 'boolean' │
459
- │ │ │ } │
460
- │ │ │ } │
461
- │ │ │ │
462
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
463
- │ const T = Type.Function([ │ type T = ( │ const T = { │
464
- | Type.String(), │ arg0: string, │ type : 'function', │
465
- │ Type.Number() │ arg1: number │ parameters: [{ │
466
- │ ], Type.Boolean()) │ ) => boolean │ type: 'string' │
467
- │ │ │ }, { │
468
- │ │ │ type: 'number' │
469
- │ │ │ }], │
470
- │ │ │ return: { │
471
- │ │ │ type: 'boolean' │
472
- │ │ │ } │
473
- │ │ │ } │
474
- │ │ │ │
475
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
476
- │ const T = Type.Uint8Array() │ type T = Uint8Array │ const T = { │
477
- │ │ │ type: 'object', │
478
- │ │ │ specialized: 'Uint8Array' │
479
- │ │ │ } │
480
- │ │ │ │
481
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
482
- │ const T = Type.Promise( │ type T = Promise<string> │ const T = { │
483
- │ Type.String() │ │ type: 'promise', │
484
- │ ) │ │ item: { │
485
- │ │ │ type: 'string' │
486
- │ │ │ } │
487
- │ │ │ } │
488
- │ │ │ │
489
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
490
- │ const T = Type.Undefined() │ type T = undefined │ const T = { │
491
- │ │ │ type: 'object', │
492
- │ │ │ specialized: 'Undefined' │
493
- │ │ │ } │
494
- │ │ │ │
495
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
496
- │ const T = Type.Void() │ type T = void │ const T = { │
497
- │ │ │ type: 'null' │
498
- │ │ │ } │
499
- │ │ │ │
500
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
501
- ```
502
-
503
- <a name='types-reference'></a>
504
-
505
- ### Reference
506
-
507
- Use `Type.Ref(...)` to create referenced types. The target type must specify an `$id`.
508
-
509
- ```typescript
510
- const T = Type.String({ $id: 'T' }) // const T = {
511
- // $id: 'T',
512
- // type: 'string'
513
- // }
514
-
515
- const R = Type.Ref(T) // const R = {
516
- // $ref: 'T'
517
- // }
518
- ```
519
-
520
- <a name='types-recursive'></a>
521
-
522
- ### Recursive
523
-
524
- Use `Type.Recursive(...)` to create recursive types.
525
-
526
- ```typescript
527
- const Node = Type.Recursive(Node => Type.Object({ // const Node = {
528
- id: Type.String(), // $id: 'Node',
529
- nodes: Type.Array(Node) // type: 'object',
530
- }), { $id: 'Node' }) // properties: {
531
- // id: {
532
- // type: 'string'
533
- // },
534
- // nodes: {
535
- // type: 'array',
536
- // items: {
537
- // $ref: 'Node'
538
- // }
539
- // }
540
- // },
541
- // required: [
542
- // 'id',
543
- // 'nodes'
544
- // ]
545
- // }
546
-
547
- type Node = Static<typeof Node> // type Node = {
548
- // id: string
549
- // nodes: Node[]
550
- // }
551
-
552
- function test(node: Node) {
553
- const id = node.nodes[0].nodes[0] // id is string
554
- .nodes[0].nodes[0]
555
- .id
556
- }
557
- ```
558
-
559
- <a name='types-generic'></a>
560
-
561
- ### Generic
562
-
563
- Use functions to create generic types. The following creates a generic `Nullable<T>` type.
564
-
565
- ```typescript
566
- import { Type, Static, TSchema } from '@sinclair/typebox'
567
-
568
- const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()])
569
-
570
- const T = Nullable(Type.String()) // const T = {
571
- // anyOf: [{
572
- // type: 'string'
573
- // }, {
574
- // type: 'null'
575
- // }]
576
- // }
577
-
578
- type T = Static<typeof T> // type T = string | null
579
-
580
- const U = Nullable(Type.Number()) // const U = {
581
- // anyOf: [{
582
- // type: 'number'
583
- // }, {
584
- // type: 'null'
585
- // }]
586
- // }
587
-
588
- type U = Static<typeof U> // type U = number | null
589
- ```
590
-
591
- <a name='types-conditional'></a>
592
-
593
- ### Conditional
594
-
595
- Use the conditional module to create [Conditional Types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html). This module implements TypeScript's structural equivalence checks to enable TypeBox types to be conditionally inferred at runtime. This module also provides the [Extract](https://www.typescriptlang.org/docs/handbook/utility-types.html#extracttype-union) and [Exclude](https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers) utility types which are expressed as conditional types in TypeScript.
596
-
597
- The conditional module is provided as an optional import.
598
-
599
- ```typescript
600
- import { Conditional } from '@sinclair/typebox/conditional'
601
- ```
602
- The following table shows the TypeBox mappings between TypeScript and JSON schema.
603
-
604
- ```typescript
605
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
606
- │ TypeBox │ TypeScript │ JSON Schema │
607
- │ │ │ │
608
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
609
- │ const T = Conditional.Extends( │ type T = │ const T = { │
610
- │ Type.String(), │ string extends number │ const: false, │
611
- │ Type.Number(), │ true : false │ type: 'boolean' │
612
- │ Type.Literal(true), │ │ } │
613
- │ Type.Literal(false) │ │ │
614
- │ ) │ │ │
615
- │ │ │ │
616
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
617
- │ const T = Conditional.Extract( │ type T = Extract< │ const T = { │
618
- │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
619
- │ Type.Literal('a'), │ 'a' | 'f' │ const: 'a' │
620
- │ Type.Literal('b'), │ > │ type: 'string' │
621
- │ Type.Literal('c') │ │ }] │
622
- │ ]), │ │ } │
623
- │ Type.Union([ │ │ │
624
- │ Type.Literal('a'), │ │ │
625
- │ Type.Literal('f') │ │ │
626
- │ ]) │ │ │
627
- │ ) │ │ │
628
- │ │ │ │
629
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
630
- │ const T = Conditional.Exclude( │ type T = Exclude< │ const T = { │
631
- │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
632
- │ Type.Literal('a'), │ 'a' │ const: 'b', │
633
- │ Type.Literal('b'), │ > │ type: 'string' │
634
- │ Type.Literal('c') │ │ }, { │
635
- │ ]), │ │ const: 'c', │
636
- │ Type.Union([ │ │ type: 'string' │
637
- │ Type.Literal('a') │ │ }] │
638
- │ ]) │ │ } │
639
- │ ) │ │ │
640
- │ │ │ │
641
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
642
- ```
643
-
644
- <a name='types-unsafe'></a>
645
-
646
- ### Unsafe
647
-
648
- Use `Type.Unsafe(...)` to create custom schemas with user defined inference rules.
649
-
650
- ```typescript
651
- const T = Type.Unsafe<string>({ type: 'number' }) // const T = {
652
- // type: 'number'
653
- // }
654
-
655
- type T = Static<typeof T> // type T = string
656
- ```
657
-
658
- 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.
659
-
660
- ```typescript
661
- import { Type, Static, TSchema } from '@sinclair/typebox'
662
-
663
- //--------------------------------------------------------------------------------------------
664
- //
665
- // Nullable<T>
666
- //
667
- //--------------------------------------------------------------------------------------------
668
-
669
- function Nullable<T extends TSchema>(schema: T) {
670
- return Type.Unsafe<Static<T> | null>({ ...schema, nullable: true })
671
- }
672
-
673
- const T = Nullable(Type.String()) // const T = {
674
- // type: 'string',
675
- // nullable: true
676
- // }
677
-
678
- type T = Static<typeof T> // type T = string | null
679
-
680
-
681
- //--------------------------------------------------------------------------------------------
682
- //
683
- // StringEnum<string[]>
684
- //
685
- //--------------------------------------------------------------------------------------------
686
-
687
- function StringEnum<T extends string[]>(values: [...T]) {
688
- return Type.Unsafe<T[number]>({ type: 'string', enum: values })
689
- }
690
-
691
- const T = StringEnum(['A', 'B', 'C']) // const T = {
692
- // enum: ['A', 'B', 'C']
693
- // }
694
-
695
- type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
696
- ```
697
-
698
- <a name='types-guards'></a>
699
-
700
- ### Guards
701
-
702
- Use the guard module to test if values are TypeBox types.
703
-
704
- ```typescript
705
- import { TypeGuard } from '@sinclair/typebox/guard'
706
-
707
- const T = Type.String()
708
-
709
- if(TypeGuard.TString(T)) {
710
-
711
- // T is TString
712
- }
713
- ```
714
-
715
- <a name='types-strict'></a>
716
-
717
- ### Strict
718
-
719
- 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.
720
-
721
- ```typescript
722
- const T = Type.Object({ // const T = {
723
- name: Type.Optional(Type.String()) // [Kind]: 'Object',
724
- }) // type: 'object',
725
- // properties: {
726
- // name: {
727
- // [Kind]: 'String',
728
- // type: 'string',
729
- // [Modifier]: 'Optional'
730
- // }
731
- // }
732
- // }
733
-
734
- const U = Type.Strict(T) // const U = {
735
- // type: 'object',
736
- // properties: {
737
- // name: {
738
- // type: 'string'
739
- // }
740
- // }
741
- // }
742
- ```
743
-
744
- <a name='values'></a>
745
-
746
- ## Values
747
-
748
- 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.
749
-
750
- ```typescript
751
- import { Value } from '@sinclair/typebox/value'
752
- ```
753
-
754
- <a name='values-create'></a>
755
-
756
- ### Create
757
-
758
- Use the Create function to create a value from a TypeBox type. TypeBox will use default values if specified.
759
-
760
- ```typescript
761
- const T = Type.Object({ x: Type.Number(), y: Type.Number({ default: 42 }) })
762
-
763
- const A = Value.Create(T) // const A = { x: 0, y: 42 }
764
- ```
765
-
766
- <a name='values-clone'></a>
767
-
768
- ### Clone
769
-
770
- Use the Clone function to deeply clone a value
771
-
772
- ```typescript
773
- const A = Value.Clone({ x: 1, y: 2, z: 3 }) // const A = { x: 1, y: 2, z: 3 }
774
- ```
775
-
776
- <a name='values-check'></a>
777
-
778
- ### Check
779
-
780
- Use the Check function to type check a value
781
-
782
- ```typescript
783
- const T = Type.Object({ x: Type.Number() })
784
-
785
- const R = Value.Check(T, { x: 1 }) // const R = true
786
- ```
787
-
788
- <a name='values-cast'></a>
789
-
790
- ### Cast
791
-
792
- 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.
793
-
794
- ```typescript
795
- const T = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false })
796
-
797
- const X = Value.Cast(T, null) // const X = { x: 0, y: 0 }
798
-
799
- const Y = Value.Cast(T, { x: 1 }) // const Y = { x: 1, y: 0 }
800
-
801
- const Z = Value.Cast(T, { x: 1, y: 2, z: 3 }) // const Z = { x: 1, y: 2 }
802
- ```
803
-
804
- <a name='values-equal'></a>
805
-
806
- ### Equal
807
-
808
- Use the Equal function to deeply check for value equality.
809
-
810
- ```typescript
811
- const R = Value.Equal( // const R = true
812
- { x: 1, y: 2, z: 3 },
813
- { x: 1, y: 2, z: 3 }
814
- )
815
- ```
816
-
817
- <a name='values-diff'></a>
818
-
819
- ### Diff
820
-
821
- Use the Diff function to produce a sequence of edits to transform one value into another.
822
-
823
- ```typescript
824
- const E = Value.Diff<any>( // const E = [
825
- { x: 1, y: 2, z: 3 }, // { type: 'update', path: '/y', value: 4 },
826
- { y: 4, z: 5, w: 6 } // { type: 'update', path: '/z', value: 5 },
827
- ) // { type: 'insert', path: '/w', value: 6 },
828
- // { type: 'delete', path: '/x' }
829
- // ]
830
- ```
831
-
832
- <a name='values-patch'></a>
833
-
834
- ### Patch
835
-
836
- Use the Patch function to apply edits
837
-
838
- ```typescript
839
- const A = { x: 1, y: 2 }
840
-
841
- const B = { x: 3 }
842
-
843
- const E = Value.Diff<any>(A, B) // const E = [
844
- // { type: 'update', path: '/x', value: 3 },
845
- // { type: 'delete', path: '/y' }
846
- // ]
847
-
848
- const C = Value.Patch<any>(A, E) // const C = { x: 3 }
849
- ```
850
-
851
-
852
- <a name='values-errors'></a>
853
-
854
- ### Errors
855
-
856
- Use the Errors function enumerate validation errors.
857
-
858
- ```typescript
859
- const T = Type.Object({ x: Type.Number(), y: Type.Number() })
860
-
861
- const R = [...Value.Errors(T, { x: '42' })] // const R = [{
862
- // schema: { type: 'number' },
863
- // path: '/x',
864
- // value: '42',
865
- // message: 'Expected number'
866
- // }, {
867
- // schema: { type: 'number' },
868
- // path: '/y',
869
- // value: undefined,
870
- // message: 'Expected number'
871
- // }]
872
- ```
873
-
874
- <a name='values-pointer'></a>
875
-
876
- ### Pointer
877
-
878
- Use ValuePointer to perform mutable updates on existing values using [RFC6901](https://www.rfc-editor.org/rfc/rfc6901) Json Pointers.
879
-
880
- ```typescript
881
- import { ValuePointer } from '@sinclair/typebox/value'
882
-
883
- const A = { x: 0, y: 0, z: 0 }
884
-
885
- ValuePointer.Set(A, '/x', 1) // const A = { x: 1, y: 0, z: 0 }
886
- ValuePointer.Set(A, '/y', 1) // const A = { x: 1, y: 1, z: 0 }
887
- ValuePointer.Set(A, '/z', 1) // const A = { x: 1, y: 1, z: 1 }
888
- ```
889
- <a name='typecheck'></a>
890
-
891
- ## TypeCheck
892
-
893
- TypeBox is written to target JSON Schema Draft 6 and can be used with any Draft 6 compliant validator. TypeBox is developed and tested against Ajv and can be used in any application already making use of this validator. Additionally, TypeBox also provides an optional type compiler that can be used to attain improved compilation and validation performance for certain application types.
894
-
895
- <a name='typecheck-ajv'></a>
896
-
897
- ### Ajv
898
-
899
- The following example shows setting up Ajv to work with TypeBox.
900
-
901
- ```bash
902
- $ npm install ajv ajv-formats --save
903
- ```
904
-
905
- ```typescript
906
- import { Type } from '@sinclair/typebox'
907
- import addFormats from 'ajv-formats'
908
- import Ajv from 'ajv'
909
-
910
- //--------------------------------------------------------------------------------------------
911
- //
912
- // Setup Ajv validator with the following options and formats
913
- //
914
- //--------------------------------------------------------------------------------------------
915
-
916
- const ajv = addFormats(new Ajv({}), [
917
- 'date-time',
918
- 'time',
919
- 'date',
920
- 'email',
921
- 'hostname',
922
- 'ipv4',
923
- 'ipv6',
924
- 'uri',
925
- 'uri-reference',
926
- 'uuid',
927
- 'uri-template',
928
- 'json-pointer',
929
- 'relative-json-pointer',
930
- 'regex'
931
- ])
932
-
933
- //--------------------------------------------------------------------------------------------
934
- //
935
- // Create a TypeBox type
936
- //
937
- //--------------------------------------------------------------------------------------------
938
-
939
- const T = Type.Object({
940
- x: Type.Number(),
941
- y: Type.Number(),
942
- z: Type.Number()
943
- })
944
-
945
- //--------------------------------------------------------------------------------------------
946
- //
947
- // Validate Data
948
- //
949
- //--------------------------------------------------------------------------------------------
950
-
951
- const R = ajv.validate(T, { x: 1, y: 2, z: 3 }) // const R = true
952
- ```
953
-
954
- <a name='typecheck-compiler'></a>
955
-
956
- ### Compiler
957
-
958
- TypeBox provides an optional high performance just-in-time (JIT) compiler and type checker that can be used in applications that require extremely fast validation. Note that this compiler is optimized for TypeBox types only where the schematics are known in advance. If defining custom types with `Type.Unsafe<T>` please consider Ajv.
959
-
960
- The compiler module is provided as an optional import.
961
-
962
- ```typescript
963
- import { TypeCompiler } from '@sinclair/typebox/compiler'
964
- ```
965
-
966
- Use the `Compile(...)` function to compile a type.
967
-
968
- ```typescript
969
- const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
970
- x: Type.Number(), // x: TNumber;
971
- y: Type.Number(), // y: TNumber;
972
- z: Type.Number() // z: TNumber;
973
- })) // }>>
974
-
975
- const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true
976
- ```
977
-
978
- Validation errors can be read with the `Errors(...)` function.
979
-
980
- ```typescript
981
- const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
982
- x: Type.Number(), // x: TNumber;
983
- y: Type.Number(), // y: TNumber;
984
- z: Type.Number() // z: TNumber;
985
- })) // }>>
986
-
987
- const value = { }
988
-
989
- const errors = [...C.Errors(value)] // const errors = [{
990
- // schema: { type: 'number' },
991
- // path: '/x',
992
- // value: undefined,
993
- // message: 'Expected number'
994
- // }, {
995
- // schema: { type: 'number' },
996
- // path: '/y',
997
- // value: undefined,
998
- // message: 'Expected number'
999
- // }, {
1000
- // schema: { type: 'number' },
1001
- // path: '/z',
1002
- // value: undefined,
1003
- // message: 'Expected number'
1004
- // }]
1005
- ```
1006
-
1007
- Compiled routines can be inspected with the `.Code()` function.
1008
-
1009
- ```typescript
1010
- const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString>
1011
-
1012
- console.log(C.Code()) // return function check(value) {
1013
- // return (
1014
- // (typeof value === 'string')
1015
- // )
1016
- // }
1017
- ```
1018
-
1019
- <a name='typecheck-formats'></a>
1020
-
1021
- ### Formats
1022
-
1023
- Use the format module to create user defined string formats. The format module is used by the Value and TypeCompiler modules only. If using Ajv, please refer to the official Ajv format documentation located [here](https://ajv.js.org/guide/formats.html).
1024
-
1025
- The format module is an optional import.
1026
-
1027
- ```typescript
1028
- import { Format } from '@sinclair/typebox/format'
1029
- ```
1030
-
1031
- The following creates a `palindrome` string format.
1032
-
1033
- ```typescript
1034
- Format.Set('palindrome', value => value === value.split('').reverse().join(''))
1035
- ```
1036
-
1037
- Once set, this format can then be used by the TypeCompiler and Value modules.
1038
-
1039
- ```typescript
1040
- const T = Type.String({ format: 'palindrome' })
1041
-
1042
- const A = TypeCompiler.Compile(T).Check('engine') // const A = false
1043
-
1044
- const B = Value.Check(T, 'kayak') // const B = true
1045
- ```
1046
-
1047
- <a name='benchmark'></a>
1048
-
1049
- ## Benchmark
1050
-
1051
- 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.0.
1052
-
1053
- For additional comparative benchmarks, please refer to [typescript-runtime-type-benchmarks](https://moltar.github.io/typescript-runtime-type-benchmarks/).
1054
-
1055
- <a name='benchmark-compile'></a>
1056
-
1057
- ### Compile
1058
-
1059
- This benchmark measures compilation performance for varying types. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/measurement/module/compile.ts).
1060
-
1061
- ```typescript
1062
- ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┐
1063
- │ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │
1064
- ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┤
1065
- │ Number │ 2000 │ ' 428 ms' │ ' 12 ms' │ ' 35.67 x' │
1066
- │ String │ 2000 │ ' 337 ms' │ ' 12 ms' │ ' 28.08 x' │
1067
- │ Boolean │ 2000 │ ' 317 ms' │ ' 11 ms' │ ' 28.82 x' │
1068
- │ Null │ 2000 │ ' 274 ms' │ ' 10 ms' │ ' 27.40 x' │
1069
- │ RegEx │ 2000 │ ' 500 ms' │ ' 18 ms' │ ' 27.78 x' │
1070
- │ ObjectA │ 2000 │ ' 2717 ms' │ ' 49 ms' │ ' 55.45 x' │
1071
- │ ObjectB │ 2000 │ ' 2854 ms' │ ' 37 ms' │ ' 77.14 x' │
1072
- │ Tuple │ 2000 │ ' 1224 ms' │ ' 21 ms' │ ' 58.29 x' │
1073
- │ Union │ 2000 │ ' 1266 ms' │ ' 23 ms' │ ' 55.04 x' │
1074
- │ Vector4 │ 2000 │ ' 1513 ms' │ ' 19 ms' │ ' 79.63 x' │
1075
- │ Matrix4 │ 2000 │ ' 841 ms' │ ' 12 ms' │ ' 70.08 x' │
1076
- │ Literal_String │ 2000 │ ' 327 ms' │ ' 8 ms' │ ' 40.88 x' │
1077
- │ Literal_Number │ 2000 │ ' 358 ms' │ ' 6 ms' │ ' 59.67 x' │
1078
- │ Literal_Boolean │ 2000 │ ' 355 ms' │ ' 5 ms' │ ' 71.00 x' │
1079
- │ Array_Number │ 2000 │ ' 685 ms' │ ' 7 ms' │ ' 97.86 x' │
1080
- │ Array_String │ 2000 │ ' 716 ms' │ ' 11 ms' │ ' 65.09 x' │
1081
- │ Array_Boolean │ 2000 │ ' 732 ms' │ ' 6 ms' │ ' 122.00 x' │
1082
- │ Array_ObjectA │ 2000 │ ' 3503 ms' │ ' 34 ms' │ ' 103.03 x' │
1083
- │ Array_ObjectB │ 2000 │ ' 3626 ms' │ ' 38 ms' │ ' 95.42 x' │
1084
- │ Array_Tuple │ 2000 │ ' 2095 ms' │ ' 21 ms' │ ' 99.76 x' │
1085
- │ Array_Union │ 2000 │ ' 1577 ms' │ ' 22 ms' │ ' 71.68 x' │
1086
- │ Array_Vector4 │ 2000 │ ' 2172 ms' │ ' 17 ms' │ ' 127.76 x' │
1087
- │ Array_Matrix4 │ 2000 │ ' 1468 ms' │ ' 19 ms' │ ' 77.26 x' │
1088
- └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┘
1089
- ```
1090
-
1091
- <a name='benchmark-validate'></a>
1092
-
1093
- ### Validate
1094
-
1095
- This benchmark measures validation performance for varying types. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/measurement/module/check.ts).
1096
-
1097
- ```typescript
1098
- ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
1099
- │ (index) │ Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │
1100
- ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
1101
- │ Number │ 1000000 │ ' 24 ms' │ ' 9 ms' │ ' 6 ms' │ ' 1.50 x' │
1102
- │ String │ 1000000 │ ' 23 ms' │ ' 19 ms' │ ' 12 ms' │ ' 1.58 x' │
1103
- │ Boolean │ 1000000 │ ' 24 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
1104
- │ Null │ 1000000 │ ' 23 ms' │ ' 18 ms' │ ' 9 ms' │ ' 2.00 x' │
1105
- │ RegEx │ 1000000 │ ' 164 ms' │ ' 46 ms' │ ' 38 ms' │ ' 1.21 x' │
1106
- │ ObjectA │ 1000000 │ ' 548 ms' │ ' 36 ms' │ ' 22 ms' │ ' 1.64 x' │
1107
- │ ObjectB │ 1000000 │ ' 1118 ms' │ ' 51 ms' │ ' 38 ms' │ ' 1.34 x' │
1108
- │ Tuple │ 1000000 │ ' 136 ms' │ ' 25 ms' │ ' 14 ms' │ ' 1.79 x' │
1109
- │ Union │ 1000000 │ ' 338 ms' │ ' 27 ms' │ ' 16 ms' │ ' 1.69 x' │
1110
- │ Recursive │ 1000000 │ ' 3251 ms' │ ' 416 ms' │ ' 98 ms' │ ' 4.24 x' │
1111
- │ Vector4 │ 1000000 │ ' 146 ms' │ ' 23 ms' │ ' 12 ms' │ ' 1.92 x' │
1112
- │ Matrix4 │ 1000000 │ ' 584 ms' │ ' 40 ms' │ ' 25 ms' │ ' 1.60 x' │
1113
- │ Literal_String │ 1000000 │ ' 46 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
1114
- │ Literal_Number │ 1000000 │ ' 46 ms' │ ' 20 ms' │ ' 10 ms' │ ' 2.00 x' │
1115
- │ Literal_Boolean │ 1000000 │ ' 47 ms' │ ' 21 ms' │ ' 10 ms' │ ' 2.10 x' │
1116
- │ Array_Number │ 1000000 │ ' 456 ms' │ ' 31 ms' │ ' 19 ms' │ ' 1.63 x' │
1117
- │ Array_String │ 1000000 │ ' 489 ms' │ ' 40 ms' │ ' 25 ms' │ ' 1.60 x' │
1118
- │ Array_Boolean │ 1000000 │ ' 458 ms' │ ' 35 ms' │ ' 27 ms' │ ' 1.30 x' │
1119
- │ Array_ObjectA │ 1000000 │ ' 13559 ms' │ ' 2568 ms' │ ' 1564 ms' │ ' 1.64 x' │
1120
- │ Array_ObjectB │ 1000000 │ ' 15863 ms' │ ' 2744 ms' │ ' 2060 ms' │ ' 1.33 x' │
1121
- │ Array_Tuple │ 1000000 │ ' 1694 ms' │ ' 96 ms' │ ' 63 ms' │ ' 1.52 x' │
1122
- │ Array_Union │ 1000000 │ ' 4736 ms' │ ' 229 ms' │ ' 86 ms' │ ' 2.66 x' │
1123
- │ Array_Recursive │ 1000000 │ ' 53804 ms' │ ' 6744 ms' │ ' 1167 ms' │ ' 5.78 x' │
1124
- │ Array_Vector4 │ 1000000 │ ' 2244 ms' │ ' 99 ms' │ ' 46 ms' │ ' 2.15 x' │
1125
- │ Array_Matrix4 │ 1000000 │ ' 11966 ms' │ ' 378 ms' │ ' 229 ms' │ ' 1.65 x' │
1126
- └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
1127
- ```
1128
-
1129
- <a name='benchmark-compression'></a>
1130
-
1131
- ### Compression
1132
-
1133
- The following table lists esbuild compiled and minified sizes for each TypeBox module.
1134
-
1135
- ```typescript
1136
- ┌──────────────────────┬────────────┬────────────┬─────────────┐
1137
- │ (index) │ Compiled │ Minified │ Compression │
1138
- ├──────────────────────┼────────────┼────────────┼─────────────┤
1139
- │ typebox/compiler │ ' 51 kb' │ ' 25 kb' │ '2.00 x' │
1140
- │ typebox/conditional │ ' 42 kb' │ ' 17 kb' │ '2.46 x' │
1141
- │ typebox/format │ ' 0 kb' │ ' 0 kb' │ '2.66 x' │
1142
- │ typebox/guard │ ' 21 kb' │ ' 10 kb' │ '2.08 x' │
1143
- │ typebox/value │ ' 74 kb' │ ' 34 kb' │ '2.16 x' │
1144
- │ typebox │ ' 11 kb' │ ' 6 kb' │ '1.91 x' │
1145
- └──────────────────────┴────────────┴────────────┴─────────────┘
1146
- ```
1147
-
1148
- <a name='contribute'></a>
1149
-
1150
- ## Contribute
1151
-
1152
- 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.
1
+ <div align='center'>
2
+
3
+ <h1>TypeBox</h1>
4
+
5
+ <p>JSON Schema Type Builder with Static Type Resolution for TypeScript</p>
6
+
7
+ <img src="https://github.com/sinclairzx81/typebox/blob/master/typebox.png?raw=true" />
8
+
9
+ <br />
10
+ <br />
11
+
12
+ [![npm version](https://badge.fury.io/js/%40sinclair%2Ftypebox.svg)](https://badge.fury.io/js/%40sinclair%2Ftypebox)
13
+ [![Downloads](https://img.shields.io/npm/dm/%40sinclair%2Ftypebox.svg)](https://www.npmjs.com/package/%40sinclair%2Ftypebox)
14
+ [![GitHub CI](https://github.com/sinclairzx81/typebox/workflows/GitHub%20CI/badge.svg)](https://github.com/sinclairzx81/typebox/actions)
15
+
16
+ </div>
17
+
18
+ <a name="Install"></a>
19
+
20
+ ## Install
21
+
22
+ Node
23
+
24
+ ```bash
25
+ $ npm install @sinclair/typebox --save
26
+ ```
27
+
28
+ Deno and ESM
29
+
30
+ ```typescript
31
+ import { Static, Type } from 'https://esm.sh/@sinclair/typebox'
32
+ ```
33
+
34
+ ## Example
35
+
36
+ ```typescript
37
+ import { Static, Type } from '@sinclair/typebox'
38
+
39
+ const T = Type.String() // const T = { type: 'string' }
40
+
41
+ type T = Static<typeof T> // type T = string
42
+ ```
43
+
44
+ <a name="Overview"></a>
45
+
46
+ ## Overview
47
+
48
+ 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.
49
+
50
+ TypeBox 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.
51
+
52
+ License MIT
53
+
54
+ ## Contents
55
+ - [Install](#install)
56
+ - [Overview](#overview)
57
+ - [Usage](#usage)
58
+ - [Types](#types)
59
+ - [Standard](#types-standard)
60
+ - [Modifiers](#types-modifiers)
61
+ - [Options](#types-options)
62
+ - [Extended](#types-extended)
63
+ - [Reference](#types-reference)
64
+ - [Recursive](#types-recursive)
65
+ - [Generic](#types-generic)
66
+ - [Conditional](#types-conditional)
67
+ - [Unsafe](#types-unsafe)
68
+ - [Guards](#types-guards)
69
+ - [Strict](#types-strict)
70
+ - [Values](#values)
71
+ - [Create](#values-create)
72
+ - [Clone](#values-clone)
73
+ - [Check](#values-check)
74
+ - [Cast](#values-cast)
75
+ - [Equal](#values-equal)
76
+ - [Diff](#values-diff)
77
+ - [Patch](#values-patch)
78
+ - [Errors](#values-errors)
79
+ - [Pointer](#values-pointer)
80
+ - [TypeCheck](#typecheck)
81
+ - [Ajv](#typecheck-ajv)
82
+ - [Compiler](#typecheck-compiler)
83
+ - [Formats](#typecheck-formats)
84
+ - [Benchmark](#benchmark)
85
+ - [Compile](#benchmark-compile)
86
+ - [Validate](#benchmark-validate)
87
+ - [Compression](#benchmark-compression)
88
+ - [Contribute](#contribute)
89
+
90
+ <a name="Example"></a>
91
+
92
+ ## Usage
93
+
94
+ The following demonstrates TypeBox's general usage.
95
+
96
+ ```typescript
97
+
98
+ import { Static, Type } from '@sinclair/typebox'
99
+
100
+ //--------------------------------------------------------------------------------------------
101
+ //
102
+ // Let's say you have the following type ...
103
+ //
104
+ //--------------------------------------------------------------------------------------------
105
+
106
+ type T = {
107
+ id: string,
108
+ name: string,
109
+ timestamp: number
110
+ }
111
+
112
+ //--------------------------------------------------------------------------------------------
113
+ //
114
+ // ... you can express this type in the following way.
115
+ //
116
+ //--------------------------------------------------------------------------------------------
117
+
118
+ const T = Type.Object({ // const T = {
119
+ id: Type.String(), // type: 'object',
120
+ name: Type.String(), // properties: {
121
+ timestamp: Type.Integer() // id: {
122
+ }) // type: 'string'
123
+ // },
124
+ // name: {
125
+ // type: 'string'
126
+ // },
127
+ // timestamp: {
128
+ // type: 'integer'
129
+ // }
130
+ // },
131
+ // required: [
132
+ // 'id',
133
+ // 'name',
134
+ // 'timestamp'
135
+ // ]
136
+ // }
137
+
138
+ //--------------------------------------------------------------------------------------------
139
+ //
140
+ // ... then infer back to the original static type this way.
141
+ //
142
+ //--------------------------------------------------------------------------------------------
143
+
144
+ type T = Static<typeof T> // type T = {
145
+ // id: string,
146
+ // name: string,
147
+ // timestamp: number
148
+ // }
149
+
150
+ //--------------------------------------------------------------------------------------------
151
+ //
152
+ // ... then use the type both as JSON schema and as a TypeScript type.
153
+ //
154
+ //--------------------------------------------------------------------------------------------
155
+
156
+ function receive(value: T) { // ... as a Type
157
+
158
+ if(JSON.validate(T, value)) { // ... as a Schema
159
+
160
+ // ok...
161
+ }
162
+ }
163
+ ```
164
+
165
+ <a name='types'></a>
166
+
167
+ ## Types
168
+
169
+ 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.
170
+
171
+ <a name='types-standard'></a>
172
+
173
+ ### Standard
174
+
175
+ The following table lists the standard TypeBox types.
176
+
177
+ ```typescript
178
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
179
+ │ TypeBox │ TypeScript │ JSON Schema │
180
+ │ │ │ │
181
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
182
+ │ const T = Type.Any() │ type T = any │ const T = { } │
183
+ │ │ │ │
184
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
185
+ │ const T = Type.Unknown() │ type T = unknown │ const T = { } │
186
+ │ │ │ │
187
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
188
+ │ const T = Type.String() │ type T = string │ const T = { │
189
+ │ │ │ type: 'string' │
190
+ │ │ │ } │
191
+ │ │ │ │
192
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
193
+ │ const T = Type.Number() │ type T = number │ const T = { │
194
+ │ │ │ type: 'number' │
195
+ │ │ │ } │
196
+ │ │ │ │
197
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
198
+ │ const T = Type.Integer() │ type T = number │ const T = { │
199
+ │ │ │ type: 'integer' │
200
+ │ │ │ } │
201
+ │ │ │ │
202
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
203
+ │ const T = Type.Boolean() │ type T = boolean │ const T = { │
204
+ │ │ │ type: 'boolean' │
205
+ │ │ │ } │
206
+ │ │ │ │
207
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
208
+ │ const T = Type.Null() │ type T = null │ const T = { │
209
+ │ │ │ type: 'null' │
210
+ │ │ │ } │
211
+ │ │ │ │
212
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
213
+ │ const T = Type.RegEx(/foo/) │ type T = string │ const T = { │
214
+ │ │ │ type: 'string', │
215
+ │ │ │ pattern: 'foo' │
216
+ │ │ │ } │
217
+ │ │ │ │
218
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
219
+ │ const T = Type.Literal(42) │ type T = 42 │ const T = { │
220
+ │ │ │ const: 42, │
221
+ │ │ │ type: 'number' │
222
+ │ │ │ } │
223
+ │ │ │ │
224
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
225
+ │ const T = Type.Array( │ type T = number[] │ const T = { │
226
+ │ Type.Number() │ │ type: 'array', │
227
+ │ ) │ │ items: { │
228
+ │ │ │ type: 'number' │
229
+ │ │ │ } │
230
+ │ │ │ } │
231
+ │ │ │ │
232
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
233
+ │ const T = Type.Object({ │ type T = { │ const T = { │
234
+ │ x: Type.Number(), │ x: number, │ type: 'object', │
235
+ │ y: Type.Number() │ y: number │ properties: { │
236
+ │ }) │ } │ x: { │
237
+ │ │ │ type: 'number' │
238
+ │ │ │ }, │
239
+ │ │ │ y: { │
240
+ │ │ │ type: 'number' │
241
+ │ │ │ } │
242
+ │ │ │ }, │
243
+ │ │ │ required: ['x', 'y'] │
244
+ │ │ │ } │
245
+ │ │ │ │
246
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
247
+ │ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │
248
+ │ Type.Number(), │ │ type: 'array', │
249
+ │ Type.Number() │ │ items: [{ │
250
+ │ ]) │ │ type: 'number' │
251
+ │ │ │ }, { │
252
+ │ │ │ type: 'number' │
253
+ │ │ │ }], │
254
+ │ │ │ additionalItems: false, │
255
+ │ │ │ minItems: 2, │
256
+ │ │ │ maxItems: 2 │
257
+ │ │ │ } │
258
+ │ │ │ │
259
+ │ │ │ │
260
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
261
+ │ enum Foo { │ enum Foo { │ const T = { │
262
+ │ A, │ A, │ anyOf: [{ │
263
+ │ B │ B │ type: 'number', │
264
+ │ } │ } │ const: 0 │
265
+ │ │ │ }, { │
266
+ │ const T = Type.Enum(Foo) │ type T = Foo │ type: 'number', │
267
+ │ │ │ const: 1 │
268
+ │ │ │ }] │
269
+ │ │ │ } │
270
+ │ │ │ │
271
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
272
+ │ const T = Type.KeyOf( │ type T = keyof { │ const T = { │
273
+ │ Type.Object({ │ x: number, │ anyOf: [{ │
274
+ │ x: Type.Number(), │ y: number │ type: 'string', │
275
+ │ y: Type.Number() │ } │ const: 'x' │
276
+ │ }) │ │ }, { │
277
+ │ ) │ │ type: 'string', │
278
+ │ │ │ const: 'y' │
279
+ │ │ │ }] │
280
+ │ │ │ } │
281
+ │ │ │ │
282
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
283
+ │ const T = Type.Union([ │ type T = string | number │ const T = { │
284
+ │ Type.String(), │ │ anyOf: [{ │
285
+ │ Type.Number() │ │ type: 'string' │
286
+ │ ]) │ │ }, { │
287
+ │ │ │ type: 'number' │
288
+ │ │ │ }] │
289
+ │ │ │ } │
290
+ │ │ │ │
291
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
292
+ │ const T = Type.Intersect([ │ type T = { │ const T = { │
293
+ │ Type.Object({ │ x: number │ type: 'object', │
294
+ │ x: Type.Number() │ } & { │ properties: { │
295
+ │ }), │ y: number │ x: { │
296
+ │ Type.Object({ │ } │ type: 'number' │
297
+ │ y: Type.Number() │ │ }, │
298
+ │ }) │ │ y: { │
299
+ │ ]) │ │ type: 'number' │
300
+ │ │ │ } │
301
+ │ │ │ }, │
302
+ │ │ │ required: ['x', 'y'] │
303
+ │ │ │ } │
304
+ │ │ │ │
305
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
306
+ │ const T = Type.Never() │ type T = never │ const T = { │
307
+ │ │ │ allOf: [{ │
308
+ │ │ │ type: 'boolean', │
309
+ │ │ │ const: false │
310
+ │ │ │ }, { │
311
+ │ │ │ type: 'boolean', │
312
+ │ │ │ const: true │
313
+ │ │ │ }] │
314
+ │ │ │ } │
315
+ │ │ │ │
316
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
317
+ │ const T = Type.Record( │ type T = Record< │ const T = { │
318
+ │ Type.String(), │ string, │ type: 'object', │
319
+ │ Type.Number() │ number, │ patternProperties: { │
320
+ │ ) │ > │ '^.*$': { │
321
+ │ │ │ type: 'number' │
322
+ │ │ │ } │
323
+ │ │ │ } │
324
+ │ │ │ } │
325
+ │ │ │ │
326
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
327
+ │ const T = Type.Partial( │ type T = Partial<{ │ const T = { │
328
+ │ Type.Object({ │ x: number, │ type: 'object', │
329
+ │ x: Type.Number(), │ y: number │ properties: { │
330
+ │ y: Type.Number() | }> │ x: { │
331
+ │ }) │ │ type: 'number' │
332
+ │ ) │ │ }, │
333
+ │ │ │ y: { │
334
+ │ │ │ type: 'number' │
335
+ │ │ │ } │
336
+ │ │ │ } │
337
+ │ │ │ } │
338
+ │ │ │ │
339
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
340
+ │ const T = Type.Required( │ type T = Required<{ │ const T = { │
341
+ │ Type.Object({ │ x?: number, │ type: 'object', │
342
+ │ x: Type.Optional( │ y?: number │ properties: { │
343
+ │ Type.Number() | }> │ x: { │
344
+ │ ), │ │ type: 'number' │
345
+ │ y: Type.Optional( │ │ }, │
346
+ │ Type.Number() │ │ y: { │
347
+ │ ) │ │ type: 'number' │
348
+ │ }) │ │ } │
349
+ │ ) │ │ }, │
350
+ │ │ │ required: ['x', 'y'] │
351
+ │ │ │ } │
352
+ │ │ │ │
353
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
354
+ │ const T = Type.Pick( │ type T = Pick<{ │ const T = { │
355
+ │ Type.Object({ │ x: number, │ type: 'object', │
356
+ │ x: Type.Number(), │ y: number │ properties: { │
357
+ │ y: Type.Number() | }, 'x'> │ x: { │
358
+ │ }), ['x'] │ │ type: 'number' │
359
+ │ ) │ │ } │
360
+ │ │ │ }, │
361
+ │ │ │ required: ['x'] │
362
+ │ │ │ } │
363
+ │ │ │ │
364
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
365
+ │ const T = Type.Omit( │ type T = Omit<{ │ const T = { │
366
+ │ Type.Object({ │ x: number, │ type: 'object', │
367
+ │ x: Type.Number(), │ y: number │ properties: { │
368
+ │ y: Type.Number() | }, 'x'> │ y: { │
369
+ │ }), ['x'] │ │ type: 'number' │
370
+ │ ) │ │ } │
371
+ │ │ │ }, │
372
+ │ │ │ required: ['y'] │
373
+ │ │ │ } │
374
+ │ │ │ │
375
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
376
+ ```
377
+
378
+ <a name='types-modifiers'></a>
379
+
380
+ ### Modifiers
381
+
382
+ 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.
383
+
384
+ ```typescript
385
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
386
+ │ TypeBox │ TypeScript │ JSON Schema │
387
+ │ │ │ │
388
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
389
+ │ const T = Type.Object({ │ type T = { │ const T = { │
390
+ │ name: Type.Optional( │ name?: string │ type: 'object', │
391
+ │ Type.String() │ } │ properties: { │
392
+ │ ) │ │ name: { │
393
+ │ }) │ │ type: 'string' │
394
+ │ │ │ } │
395
+ │ │ │ } │
396
+ │ │ │ } │
397
+ │ │ │ │
398
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
399
+ │ const T = Type.Object({ │ type T = { │ const T = { │
400
+ │ name: Type.Readonly( │ readonly name: string │ type: 'object', │
401
+ │ Type.String() │ } │ properties: { │
402
+ │ ) │ │ name: { │
403
+ │ }) │ │ type: 'string' │
404
+ │ │ │ } │
405
+ │ │ │ }, │
406
+ │ │ │ required: ['name'] │
407
+ │ │ │ } │
408
+ │ │ │ │
409
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
410
+ │ const T = Type.Object({ │ type T = { │ const T = { │
411
+ │ name: Type.ReadonlyOptional( │ readonly name?: string │ type: 'object', │
412
+ │ Type.String() │ } │ properties: { │
413
+ │ ) │ │ name: { │
414
+ │ }) │ │ type: 'string' │
415
+ │ │ │ } │
416
+ │ │ │ } │
417
+ │ │ │ } │
418
+ │ │ │ │
419
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
420
+ ```
421
+
422
+ <a name='types-options'></a>
423
+
424
+ ### Options
425
+
426
+ You can pass additional JSON schema options on the last argument of any given type. The following are some examples.
427
+
428
+ ```typescript
429
+ // string must be an email
430
+ const T = Type.String({ format: 'email' })
431
+
432
+ // number must be a multiple of 2
433
+ const T = Type.Number({ multipleOf: 2 })
434
+
435
+ // array must have at least 5 integer values
436
+ const T = Type.Array(Type.Integer(), { minItems: 5 })
437
+ ```
438
+
439
+ <a name='types-extended'></a>
440
+
441
+ ### Extended
442
+
443
+ In addition to JSON schema types, TypeBox provides several extended types that allow for the composition of `function` and `constructor` types. 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.
444
+
445
+ ```typescript
446
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
447
+ │ TypeBox │ TypeScript │ Extended Schema │
448
+ │ │ │ │
449
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
450
+ │ const T = Type.Constructor([ │ type T = new ( │ const T = { │
451
+ │ Type.String(), │ arg0: string, │ type: 'constructor' │
452
+ │ Type.Number() │ arg1: number │ parameters: [{ │
453
+ │ ], Type.Boolean()) │ ) => boolean │ type: 'string' │
454
+ │ │ │ }, { │
455
+ │ │ │ type: 'number' │
456
+ │ │ │ }], │
457
+ │ │ │ return: { │
458
+ │ │ │ type: 'boolean' │
459
+ │ │ │ } │
460
+ │ │ │ } │
461
+ │ │ │ │
462
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
463
+ │ const T = Type.Function([ │ type T = ( │ const T = { │
464
+ | Type.String(), │ arg0: string, │ type : 'function', │
465
+ │ Type.Number() │ arg1: number │ parameters: [{ │
466
+ │ ], Type.Boolean()) │ ) => boolean │ type: 'string' │
467
+ │ │ │ }, { │
468
+ │ │ │ type: 'number' │
469
+ │ │ │ }], │
470
+ │ │ │ return: { │
471
+ │ │ │ type: 'boolean' │
472
+ │ │ │ } │
473
+ │ │ │ } │
474
+ │ │ │ │
475
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
476
+ │ const T = Type.Uint8Array() │ type T = Uint8Array │ const T = { │
477
+ │ │ │ type: 'object', │
478
+ │ │ │ specialized: 'Uint8Array' │
479
+ │ │ │ } │
480
+ │ │ │ │
481
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
482
+ │ const T = Type.Promise( │ type T = Promise<string> │ const T = { │
483
+ │ Type.String() │ │ type: 'promise', │
484
+ │ ) │ │ item: { │
485
+ │ │ │ type: 'string' │
486
+ │ │ │ } │
487
+ │ │ │ } │
488
+ │ │ │ │
489
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
490
+ │ const T = Type.Undefined() │ type T = undefined │ const T = { │
491
+ │ │ │ type: 'object', │
492
+ │ │ │ specialized: 'Undefined' │
493
+ │ │ │ } │
494
+ │ │ │ │
495
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
496
+ │ const T = Type.Void() │ type T = void │ const T = { │
497
+ │ │ │ type: 'null' │
498
+ │ │ │ } │
499
+ │ │ │ │
500
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
501
+ ```
502
+
503
+ <a name='types-reference'></a>
504
+
505
+ ### Reference
506
+
507
+ Use `Type.Ref(...)` to create referenced types. The target type must specify an `$id`.
508
+
509
+ ```typescript
510
+ const T = Type.String({ $id: 'T' }) // const T = {
511
+ // $id: 'T',
512
+ // type: 'string'
513
+ // }
514
+
515
+ const R = Type.Ref(T) // const R = {
516
+ // $ref: 'T'
517
+ // }
518
+ ```
519
+
520
+ <a name='types-recursive'></a>
521
+
522
+ ### Recursive
523
+
524
+ Use `Type.Recursive(...)` to create recursive types.
525
+
526
+ ```typescript
527
+ const Node = Type.Recursive(Node => Type.Object({ // const Node = {
528
+ id: Type.String(), // $id: 'Node',
529
+ nodes: Type.Array(Node) // type: 'object',
530
+ }), { $id: 'Node' }) // properties: {
531
+ // id: {
532
+ // type: 'string'
533
+ // },
534
+ // nodes: {
535
+ // type: 'array',
536
+ // items: {
537
+ // $ref: 'Node'
538
+ // }
539
+ // }
540
+ // },
541
+ // required: [
542
+ // 'id',
543
+ // 'nodes'
544
+ // ]
545
+ // }
546
+
547
+ type Node = Static<typeof Node> // type Node = {
548
+ // id: string
549
+ // nodes: Node[]
550
+ // }
551
+
552
+ function test(node: Node) {
553
+ const id = node.nodes[0].nodes[0] // id is string
554
+ .nodes[0].nodes[0]
555
+ .id
556
+ }
557
+ ```
558
+
559
+ <a name='types-generic'></a>
560
+
561
+ ### Generic
562
+
563
+ Use functions to create generic types. The following creates a generic `Nullable<T>` type.
564
+
565
+ ```typescript
566
+ import { Type, Static, TSchema } from '@sinclair/typebox'
567
+
568
+ const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()])
569
+
570
+ const T = Nullable(Type.String()) // const T = {
571
+ // anyOf: [{
572
+ // type: 'string'
573
+ // }, {
574
+ // type: 'null'
575
+ // }]
576
+ // }
577
+
578
+ type T = Static<typeof T> // type T = string | null
579
+
580
+ const U = Nullable(Type.Number()) // const U = {
581
+ // anyOf: [{
582
+ // type: 'number'
583
+ // }, {
584
+ // type: 'null'
585
+ // }]
586
+ // }
587
+
588
+ type U = Static<typeof U> // type U = number | null
589
+ ```
590
+
591
+ <a name='types-conditional'></a>
592
+
593
+ ### Conditional
594
+
595
+ Use the conditional module to create [Conditional Types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html). This module implements TypeScript's structural equivalence checks to enable TypeBox types to be conditionally inferred at runtime. This module also provides the [Extract](https://www.typescriptlang.org/docs/handbook/utility-types.html#extracttype-union) and [Exclude](https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers) utility types which are expressed as conditional types in TypeScript.
596
+
597
+ The conditional module is provided as an optional import.
598
+
599
+ ```typescript
600
+ import { Conditional } from '@sinclair/typebox/conditional'
601
+ ```
602
+ The following table shows the TypeBox mappings between TypeScript and JSON schema.
603
+
604
+ ```typescript
605
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
606
+ │ TypeBox │ TypeScript │ JSON Schema │
607
+ │ │ │ │
608
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
609
+ │ const T = Conditional.Extends( │ type T = │ const T = { │
610
+ │ Type.String(), │ string extends number │ const: false, │
611
+ │ Type.Number(), │ true : false │ type: 'boolean' │
612
+ │ Type.Literal(true), │ │ } │
613
+ │ Type.Literal(false) │ │ │
614
+ │ ) │ │ │
615
+ │ │ │ │
616
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
617
+ │ const T = Conditional.Extract( │ type T = Extract< │ const T = { │
618
+ │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
619
+ │ Type.Literal('a'), │ 'a' | 'f' │ const: 'a' │
620
+ │ Type.Literal('b'), │ > │ type: 'string' │
621
+ │ Type.Literal('c') │ │ }] │
622
+ │ ]), │ │ } │
623
+ │ Type.Union([ │ │ │
624
+ │ Type.Literal('a'), │ │ │
625
+ │ Type.Literal('f') │ │ │
626
+ │ ]) │ │ │
627
+ │ ) │ │ │
628
+ │ │ │ │
629
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
630
+ │ const T = Conditional.Exclude( │ type T = Exclude< │ const T = { │
631
+ │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
632
+ │ Type.Literal('a'), │ 'a' │ const: 'b', │
633
+ │ Type.Literal('b'), │ > │ type: 'string' │
634
+ │ Type.Literal('c') │ │ }, { │
635
+ │ ]), │ │ const: 'c', │
636
+ │ Type.Union([ │ │ type: 'string' │
637
+ │ Type.Literal('a') │ │ }] │
638
+ │ ]) │ │ } │
639
+ │ ) │ │ │
640
+ │ │ │ │
641
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
642
+ ```
643
+
644
+ <a name='types-unsafe'></a>
645
+
646
+ ### Unsafe
647
+
648
+ Use `Type.Unsafe(...)` to create custom schemas with user defined inference rules.
649
+
650
+ ```typescript
651
+ const T = Type.Unsafe<string>({ type: 'number' }) // const T = {
652
+ // type: 'number'
653
+ // }
654
+
655
+ type T = Static<typeof T> // type T = string
656
+ ```
657
+
658
+ 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.
659
+
660
+ ```typescript
661
+ import { Type, Static, TSchema } from '@sinclair/typebox'
662
+
663
+ //--------------------------------------------------------------------------------------------
664
+ //
665
+ // Nullable<T>
666
+ //
667
+ //--------------------------------------------------------------------------------------------
668
+
669
+ function Nullable<T extends TSchema>(schema: T) {
670
+ return Type.Unsafe<Static<T> | null>({ ...schema, nullable: true })
671
+ }
672
+
673
+ const T = Nullable(Type.String()) // const T = {
674
+ // type: 'string',
675
+ // nullable: true
676
+ // }
677
+
678
+ type T = Static<typeof T> // type T = string | null
679
+
680
+
681
+ //--------------------------------------------------------------------------------------------
682
+ //
683
+ // StringEnum<string[]>
684
+ //
685
+ //--------------------------------------------------------------------------------------------
686
+
687
+ function StringEnum<T extends string[]>(values: [...T]) {
688
+ return Type.Unsafe<T[number]>({ type: 'string', enum: values })
689
+ }
690
+
691
+ const T = StringEnum(['A', 'B', 'C']) // const T = {
692
+ // enum: ['A', 'B', 'C']
693
+ // }
694
+
695
+ type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
696
+ ```
697
+
698
+ <a name='types-guards'></a>
699
+
700
+ ### Guards
701
+
702
+ Use the guard module to test if values are TypeBox types.
703
+
704
+ ```typescript
705
+ import { TypeGuard } from '@sinclair/typebox/guard'
706
+
707
+ const T = Type.String()
708
+
709
+ if(TypeGuard.TString(T)) {
710
+
711
+ // T is TString
712
+ }
713
+ ```
714
+
715
+ <a name='types-strict'></a>
716
+
717
+ ### Strict
718
+
719
+ 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.
720
+
721
+ ```typescript
722
+ const T = Type.Object({ // const T = {
723
+ name: Type.Optional(Type.String()) // [Kind]: 'Object',
724
+ }) // type: 'object',
725
+ // properties: {
726
+ // name: {
727
+ // [Kind]: 'String',
728
+ // type: 'string',
729
+ // [Modifier]: 'Optional'
730
+ // }
731
+ // }
732
+ // }
733
+
734
+ const U = Type.Strict(T) // const U = {
735
+ // type: 'object',
736
+ // properties: {
737
+ // name: {
738
+ // type: 'string'
739
+ // }
740
+ // }
741
+ // }
742
+ ```
743
+
744
+ <a name='values'></a>
745
+
746
+ ## Values
747
+
748
+ 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.
749
+
750
+ ```typescript
751
+ import { Value } from '@sinclair/typebox/value'
752
+ ```
753
+
754
+ <a name='values-create'></a>
755
+
756
+ ### Create
757
+
758
+ Use the Create function to create a value from a TypeBox type. TypeBox will use default values if specified.
759
+
760
+ ```typescript
761
+ const T = Type.Object({ x: Type.Number(), y: Type.Number({ default: 42 }) })
762
+
763
+ const A = Value.Create(T) // const A = { x: 0, y: 42 }
764
+ ```
765
+
766
+ <a name='values-clone'></a>
767
+
768
+ ### Clone
769
+
770
+ Use the Clone function to deeply clone a value
771
+
772
+ ```typescript
773
+ const A = Value.Clone({ x: 1, y: 2, z: 3 }) // const A = { x: 1, y: 2, z: 3 }
774
+ ```
775
+
776
+ <a name='values-check'></a>
777
+
778
+ ### Check
779
+
780
+ Use the Check function to type check a value
781
+
782
+ ```typescript
783
+ const T = Type.Object({ x: Type.Number() })
784
+
785
+ const R = Value.Check(T, { x: 1 }) // const R = true
786
+ ```
787
+
788
+ <a name='values-cast'></a>
789
+
790
+ ### Cast
791
+
792
+ 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.
793
+
794
+ ```typescript
795
+ const T = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false })
796
+
797
+ const X = Value.Cast(T, null) // const X = { x: 0, y: 0 }
798
+
799
+ const Y = Value.Cast(T, { x: 1 }) // const Y = { x: 1, y: 0 }
800
+
801
+ const Z = Value.Cast(T, { x: 1, y: 2, z: 3 }) // const Z = { x: 1, y: 2 }
802
+ ```
803
+
804
+ <a name='values-equal'></a>
805
+
806
+ ### Equal
807
+
808
+ Use the Equal function to deeply check for value equality.
809
+
810
+ ```typescript
811
+ const R = Value.Equal( // const R = true
812
+ { x: 1, y: 2, z: 3 },
813
+ { x: 1, y: 2, z: 3 }
814
+ )
815
+ ```
816
+
817
+ <a name='values-diff'></a>
818
+
819
+ ### Diff
820
+
821
+ Use the Diff function to produce a sequence of edits to transform one value into another.
822
+
823
+ ```typescript
824
+ const E = Value.Diff<any>( // const E = [
825
+ { x: 1, y: 2, z: 3 }, // { type: 'update', path: '/y', value: 4 },
826
+ { y: 4, z: 5, w: 6 } // { type: 'update', path: '/z', value: 5 },
827
+ ) // { type: 'insert', path: '/w', value: 6 },
828
+ // { type: 'delete', path: '/x' }
829
+ // ]
830
+ ```
831
+
832
+ <a name='values-patch'></a>
833
+
834
+ ### Patch
835
+
836
+ Use the Patch function to apply edits
837
+
838
+ ```typescript
839
+ const A = { x: 1, y: 2 }
840
+
841
+ const B = { x: 3 }
842
+
843
+ const E = Value.Diff<any>(A, B) // const E = [
844
+ // { type: 'update', path: '/x', value: 3 },
845
+ // { type: 'delete', path: '/y' }
846
+ // ]
847
+
848
+ const C = Value.Patch<any>(A, E) // const C = { x: 3 }
849
+ ```
850
+
851
+
852
+ <a name='values-errors'></a>
853
+
854
+ ### Errors
855
+
856
+ Use the Errors function enumerate validation errors.
857
+
858
+ ```typescript
859
+ const T = Type.Object({ x: Type.Number(), y: Type.Number() })
860
+
861
+ const R = [...Value.Errors(T, { x: '42' })] // const R = [{
862
+ // schema: { type: 'number' },
863
+ // path: '/x',
864
+ // value: '42',
865
+ // message: 'Expected number'
866
+ // }, {
867
+ // schema: { type: 'number' },
868
+ // path: '/y',
869
+ // value: undefined,
870
+ // message: 'Expected number'
871
+ // }]
872
+ ```
873
+
874
+ <a name='values-pointer'></a>
875
+
876
+ ### Pointer
877
+
878
+ Use ValuePointer to perform mutable updates on existing values using [RFC6901](https://www.rfc-editor.org/rfc/rfc6901) Json Pointers.
879
+
880
+ ```typescript
881
+ import { ValuePointer } from '@sinclair/typebox/value'
882
+
883
+ const A = { x: 0, y: 0, z: 0 }
884
+
885
+ ValuePointer.Set(A, '/x', 1) // const A = { x: 1, y: 0, z: 0 }
886
+ ValuePointer.Set(A, '/y', 1) // const A = { x: 1, y: 1, z: 0 }
887
+ ValuePointer.Set(A, '/z', 1) // const A = { x: 1, y: 1, z: 1 }
888
+ ```
889
+ <a name='typecheck'></a>
890
+
891
+ ## TypeCheck
892
+
893
+ TypeBox is written to target JSON Schema Draft 6 and can be used with any Draft 6 compliant validator. TypeBox is developed and tested against Ajv and can be used in any application already making use of this validator. Additionally, TypeBox also provides an optional type compiler that can be used to attain improved compilation and validation performance for certain application types.
894
+
895
+ <a name='typecheck-ajv'></a>
896
+
897
+ ### Ajv
898
+
899
+ The following example shows setting up Ajv to work with TypeBox.
900
+
901
+ ```bash
902
+ $ npm install ajv ajv-formats --save
903
+ ```
904
+
905
+ ```typescript
906
+ import { Type } from '@sinclair/typebox'
907
+ import addFormats from 'ajv-formats'
908
+ import Ajv from 'ajv'
909
+
910
+ //--------------------------------------------------------------------------------------------
911
+ //
912
+ // Setup Ajv validator with the following options and formats
913
+ //
914
+ //--------------------------------------------------------------------------------------------
915
+
916
+ const ajv = addFormats(new Ajv({}), [
917
+ 'date-time',
918
+ 'time',
919
+ 'date',
920
+ 'email',
921
+ 'hostname',
922
+ 'ipv4',
923
+ 'ipv6',
924
+ 'uri',
925
+ 'uri-reference',
926
+ 'uuid',
927
+ 'uri-template',
928
+ 'json-pointer',
929
+ 'relative-json-pointer',
930
+ 'regex'
931
+ ])
932
+
933
+ //--------------------------------------------------------------------------------------------
934
+ //
935
+ // Create a TypeBox type
936
+ //
937
+ //--------------------------------------------------------------------------------------------
938
+
939
+ const T = Type.Object({
940
+ x: Type.Number(),
941
+ y: Type.Number(),
942
+ z: Type.Number()
943
+ })
944
+
945
+ //--------------------------------------------------------------------------------------------
946
+ //
947
+ // Validate Data
948
+ //
949
+ //--------------------------------------------------------------------------------------------
950
+
951
+ const R = ajv.validate(T, { x: 1, y: 2, z: 3 }) // const R = true
952
+ ```
953
+
954
+ <a name='typecheck-compiler'></a>
955
+
956
+ ### Compiler
957
+
958
+ TypeBox provides an optional high performance just-in-time (JIT) compiler and type checker that can be used in applications that require extremely fast validation. Note that this compiler is optimized for TypeBox types only where the schematics are known in advance. If defining custom types with `Type.Unsafe<T>` please consider Ajv.
959
+
960
+ The compiler module is provided as an optional import.
961
+
962
+ ```typescript
963
+ import { TypeCompiler } from '@sinclair/typebox/compiler'
964
+ ```
965
+
966
+ Use the `Compile(...)` function to compile a type.
967
+
968
+ ```typescript
969
+ const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
970
+ x: Type.Number(), // x: TNumber;
971
+ y: Type.Number(), // y: TNumber;
972
+ z: Type.Number() // z: TNumber;
973
+ })) // }>>
974
+
975
+ const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true
976
+ ```
977
+
978
+ Validation errors can be read with the `Errors(...)` function.
979
+
980
+ ```typescript
981
+ const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
982
+ x: Type.Number(), // x: TNumber;
983
+ y: Type.Number(), // y: TNumber;
984
+ z: Type.Number() // z: TNumber;
985
+ })) // }>>
986
+
987
+ const value = { }
988
+
989
+ const errors = [...C.Errors(value)] // const errors = [{
990
+ // schema: { type: 'number' },
991
+ // path: '/x',
992
+ // value: undefined,
993
+ // message: 'Expected number'
994
+ // }, {
995
+ // schema: { type: 'number' },
996
+ // path: '/y',
997
+ // value: undefined,
998
+ // message: 'Expected number'
999
+ // }, {
1000
+ // schema: { type: 'number' },
1001
+ // path: '/z',
1002
+ // value: undefined,
1003
+ // message: 'Expected number'
1004
+ // }]
1005
+ ```
1006
+
1007
+ Compiled routines can be inspected with the `.Code()` function.
1008
+
1009
+ ```typescript
1010
+ const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString>
1011
+
1012
+ console.log(C.Code()) // return function check(value) {
1013
+ // return (
1014
+ // (typeof value === 'string')
1015
+ // )
1016
+ // }
1017
+ ```
1018
+
1019
+ <a name='typecheck-formats'></a>
1020
+
1021
+ ### Formats
1022
+
1023
+ Use the format module to create user defined string formats. The format module is used by the Value and TypeCompiler modules only. If using Ajv, please refer to the official Ajv format documentation located [here](https://ajv.js.org/guide/formats.html).
1024
+
1025
+ The format module is an optional import.
1026
+
1027
+ ```typescript
1028
+ import { Format } from '@sinclair/typebox/format'
1029
+ ```
1030
+
1031
+ The following creates a `palindrome` string format.
1032
+
1033
+ ```typescript
1034
+ Format.Set('palindrome', value => value === value.split('').reverse().join(''))
1035
+ ```
1036
+
1037
+ Once set, this format can then be used by the TypeCompiler and Value modules.
1038
+
1039
+ ```typescript
1040
+ const T = Type.String({ format: 'palindrome' })
1041
+
1042
+ const A = TypeCompiler.Compile(T).Check('engine') // const A = false
1043
+
1044
+ const B = Value.Check(T, 'kayak') // const B = true
1045
+ ```
1046
+
1047
+ <a name='benchmark'></a>
1048
+
1049
+ ## Benchmark
1050
+
1051
+ 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.0.
1052
+
1053
+ For additional comparative benchmarks, please refer to [typescript-runtime-type-benchmarks](https://moltar.github.io/typescript-runtime-type-benchmarks/).
1054
+
1055
+ <a name='benchmark-compile'></a>
1056
+
1057
+ ### Compile
1058
+
1059
+ This benchmark measures compilation performance for varying types. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/measurement/module/compile.ts).
1060
+
1061
+ ```typescript
1062
+ ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┐
1063
+ │ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │
1064
+ ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┤
1065
+ │ Number │ 2000 │ ' 428 ms' │ ' 12 ms' │ ' 35.67 x' │
1066
+ │ String │ 2000 │ ' 337 ms' │ ' 12 ms' │ ' 28.08 x' │
1067
+ │ Boolean │ 2000 │ ' 317 ms' │ ' 11 ms' │ ' 28.82 x' │
1068
+ │ Null │ 2000 │ ' 274 ms' │ ' 10 ms' │ ' 27.40 x' │
1069
+ │ RegEx │ 2000 │ ' 500 ms' │ ' 18 ms' │ ' 27.78 x' │
1070
+ │ ObjectA │ 2000 │ ' 2717 ms' │ ' 49 ms' │ ' 55.45 x' │
1071
+ │ ObjectB │ 2000 │ ' 2854 ms' │ ' 37 ms' │ ' 77.14 x' │
1072
+ │ Tuple │ 2000 │ ' 1224 ms' │ ' 21 ms' │ ' 58.29 x' │
1073
+ │ Union │ 2000 │ ' 1266 ms' │ ' 23 ms' │ ' 55.04 x' │
1074
+ │ Vector4 │ 2000 │ ' 1513 ms' │ ' 19 ms' │ ' 79.63 x' │
1075
+ │ Matrix4 │ 2000 │ ' 841 ms' │ ' 12 ms' │ ' 70.08 x' │
1076
+ │ Literal_String │ 2000 │ ' 327 ms' │ ' 8 ms' │ ' 40.88 x' │
1077
+ │ Literal_Number │ 2000 │ ' 358 ms' │ ' 6 ms' │ ' 59.67 x' │
1078
+ │ Literal_Boolean │ 2000 │ ' 355 ms' │ ' 5 ms' │ ' 71.00 x' │
1079
+ │ Array_Number │ 2000 │ ' 685 ms' │ ' 7 ms' │ ' 97.86 x' │
1080
+ │ Array_String │ 2000 │ ' 716 ms' │ ' 11 ms' │ ' 65.09 x' │
1081
+ │ Array_Boolean │ 2000 │ ' 732 ms' │ ' 6 ms' │ ' 122.00 x' │
1082
+ │ Array_ObjectA │ 2000 │ ' 3503 ms' │ ' 34 ms' │ ' 103.03 x' │
1083
+ │ Array_ObjectB │ 2000 │ ' 3626 ms' │ ' 38 ms' │ ' 95.42 x' │
1084
+ │ Array_Tuple │ 2000 │ ' 2095 ms' │ ' 21 ms' │ ' 99.76 x' │
1085
+ │ Array_Union │ 2000 │ ' 1577 ms' │ ' 22 ms' │ ' 71.68 x' │
1086
+ │ Array_Vector4 │ 2000 │ ' 2172 ms' │ ' 17 ms' │ ' 127.76 x' │
1087
+ │ Array_Matrix4 │ 2000 │ ' 1468 ms' │ ' 19 ms' │ ' 77.26 x' │
1088
+ └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┘
1089
+ ```
1090
+
1091
+ <a name='benchmark-validate'></a>
1092
+
1093
+ ### Validate
1094
+
1095
+ This benchmark measures validation performance for varying types. You can review this benchmark [here](https://github.com/sinclairzx81/typebox/blob/master/benchmark/measurement/module/check.ts).
1096
+
1097
+ ```typescript
1098
+ ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
1099
+ │ (index) │ Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │
1100
+ ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
1101
+ │ Number │ 1000000 │ ' 24 ms' │ ' 9 ms' │ ' 6 ms' │ ' 1.50 x' │
1102
+ │ String │ 1000000 │ ' 23 ms' │ ' 19 ms' │ ' 12 ms' │ ' 1.58 x' │
1103
+ │ Boolean │ 1000000 │ ' 24 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
1104
+ │ Null │ 1000000 │ ' 23 ms' │ ' 18 ms' │ ' 9 ms' │ ' 2.00 x' │
1105
+ │ RegEx │ 1000000 │ ' 164 ms' │ ' 46 ms' │ ' 38 ms' │ ' 1.21 x' │
1106
+ │ ObjectA │ 1000000 │ ' 548 ms' │ ' 36 ms' │ ' 22 ms' │ ' 1.64 x' │
1107
+ │ ObjectB │ 1000000 │ ' 1118 ms' │ ' 51 ms' │ ' 38 ms' │ ' 1.34 x' │
1108
+ │ Tuple │ 1000000 │ ' 136 ms' │ ' 25 ms' │ ' 14 ms' │ ' 1.79 x' │
1109
+ │ Union │ 1000000 │ ' 338 ms' │ ' 27 ms' │ ' 16 ms' │ ' 1.69 x' │
1110
+ │ Recursive │ 1000000 │ ' 3251 ms' │ ' 416 ms' │ ' 98 ms' │ ' 4.24 x' │
1111
+ │ Vector4 │ 1000000 │ ' 146 ms' │ ' 23 ms' │ ' 12 ms' │ ' 1.92 x' │
1112
+ │ Matrix4 │ 1000000 │ ' 584 ms' │ ' 40 ms' │ ' 25 ms' │ ' 1.60 x' │
1113
+ │ Literal_String │ 1000000 │ ' 46 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
1114
+ │ Literal_Number │ 1000000 │ ' 46 ms' │ ' 20 ms' │ ' 10 ms' │ ' 2.00 x' │
1115
+ │ Literal_Boolean │ 1000000 │ ' 47 ms' │ ' 21 ms' │ ' 10 ms' │ ' 2.10 x' │
1116
+ │ Array_Number │ 1000000 │ ' 456 ms' │ ' 31 ms' │ ' 19 ms' │ ' 1.63 x' │
1117
+ │ Array_String │ 1000000 │ ' 489 ms' │ ' 40 ms' │ ' 25 ms' │ ' 1.60 x' │
1118
+ │ Array_Boolean │ 1000000 │ ' 458 ms' │ ' 35 ms' │ ' 27 ms' │ ' 1.30 x' │
1119
+ │ Array_ObjectA │ 1000000 │ ' 13559 ms' │ ' 2568 ms' │ ' 1564 ms' │ ' 1.64 x' │
1120
+ │ Array_ObjectB │ 1000000 │ ' 15863 ms' │ ' 2744 ms' │ ' 2060 ms' │ ' 1.33 x' │
1121
+ │ Array_Tuple │ 1000000 │ ' 1694 ms' │ ' 96 ms' │ ' 63 ms' │ ' 1.52 x' │
1122
+ │ Array_Union │ 1000000 │ ' 4736 ms' │ ' 229 ms' │ ' 86 ms' │ ' 2.66 x' │
1123
+ │ Array_Recursive │ 1000000 │ ' 53804 ms' │ ' 6744 ms' │ ' 1167 ms' │ ' 5.78 x' │
1124
+ │ Array_Vector4 │ 1000000 │ ' 2244 ms' │ ' 99 ms' │ ' 46 ms' │ ' 2.15 x' │
1125
+ │ Array_Matrix4 │ 1000000 │ ' 11966 ms' │ ' 378 ms' │ ' 229 ms' │ ' 1.65 x' │
1126
+ └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
1127
+ ```
1128
+
1129
+ <a name='benchmark-compression'></a>
1130
+
1131
+ ### Compression
1132
+
1133
+ The following table lists esbuild compiled and minified sizes for each TypeBox module.
1134
+
1135
+ ```typescript
1136
+ ┌──────────────────────┬────────────┬────────────┬─────────────┐
1137
+ │ (index) │ Compiled │ Minified │ Compression │
1138
+ ├──────────────────────┼────────────┼────────────┼─────────────┤
1139
+ │ typebox/compiler │ ' 51 kb' │ ' 25 kb' │ '2.00 x' │
1140
+ │ typebox/conditional │ ' 42 kb' │ ' 17 kb' │ '2.46 x' │
1141
+ │ typebox/format │ ' 0 kb' │ ' 0 kb' │ '2.66 x' │
1142
+ │ typebox/guard │ ' 21 kb' │ ' 10 kb' │ '2.08 x' │
1143
+ │ typebox/value │ ' 74 kb' │ ' 34 kb' │ '2.16 x' │
1144
+ │ typebox │ ' 11 kb' │ ' 6 kb' │ '1.91 x' │
1145
+ └──────────────────────┴────────────┴────────────┴─────────────┘
1146
+ ```
1147
+
1148
+ <a name='contribute'></a>
1149
+
1150
+ ## Contribute
1151
+
1152
+ 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.