@sinclair/typebox 0.25.23 → 0.25.25

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 (61) hide show
  1. package/compiler/compiler.d.ts +25 -28
  2. package/compiler/compiler.js +495 -495
  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 +685 -685
  11. package/custom/custom.d.ts +12 -12
  12. package/custom/custom.js +55 -55
  13. package/custom/index.d.ts +1 -1
  14. package/custom/index.js +44 -44
  15. package/errors/errors.d.ts +67 -67
  16. package/errors/errors.js +472 -468
  17. package/errors/index.d.ts +1 -1
  18. package/errors/index.js +44 -44
  19. package/format/format.d.ts +12 -12
  20. package/format/format.js +55 -55
  21. package/format/index.d.ts +1 -1
  22. package/format/index.js +44 -44
  23. package/guard/extends.d.ts +10 -0
  24. package/guard/extends.js +50 -0
  25. package/guard/guard.d.ts +60 -60
  26. package/guard/guard.js +440 -440
  27. package/guard/index.d.ts +2 -1
  28. package/guard/index.js +45 -44
  29. package/hash/hash.d.ts +8 -8
  30. package/hash/hash.js +183 -183
  31. package/hash/index.d.ts +1 -1
  32. package/hash/index.js +44 -44
  33. package/license +22 -22
  34. package/package.json +55 -52
  35. package/readme.md +1237 -1325
  36. package/system/index.d.ts +1 -1
  37. package/system/index.js +44 -44
  38. package/system/system.d.ts +17 -17
  39. package/system/system.js +69 -69
  40. package/typebox.d.ts +422 -422
  41. package/typebox.js +388 -388
  42. package/value/cast.d.ts +26 -26
  43. package/value/cast.js +415 -420
  44. package/value/check.d.ts +8 -8
  45. package/value/check.js +405 -395
  46. package/value/clone.d.ts +3 -3
  47. package/value/clone.js +71 -71
  48. package/value/create.d.ts +14 -14
  49. package/value/create.js +378 -388
  50. package/value/delta.d.ts +43 -43
  51. package/value/delta.js +204 -204
  52. package/value/equal.d.ts +3 -3
  53. package/value/equal.js +80 -80
  54. package/value/index.d.ts +4 -4
  55. package/value/index.js +53 -53
  56. package/value/is.d.ts +11 -11
  57. package/value/is.js +53 -53
  58. package/value/pointer.d.ts +24 -24
  59. package/value/pointer.js +142 -142
  60. package/value/value.d.ts +32 -32
  61. package/value/value.js +87 -87
package/readme.md CHANGED
@@ -1,1325 +1,1237 @@
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
- ### npm
23
- ```bash
24
- $ npm install @sinclair/typebox --save
25
- ```
26
-
27
- ### deno
28
- ```typescript
29
- import { Static, Type } from 'npm:@sinclair/typebox'
30
- ```
31
-
32
- ### esm
33
-
34
- ```typescript
35
- import { Static, Type } from 'https://esm.sh/@sinclair/typebox'
36
- ```
37
-
38
- ## Usage
39
-
40
- ```typescript
41
- import { Static, Type } from '@sinclair/typebox'
42
-
43
- const T = Type.Object({ // const T = {
44
- x: Type.Number(), // type: 'object',
45
- y: Type.Number(), // required: ['x', 'y', 'z'],
46
- z: Type.Number() // properties: {
47
- }) // x: { type: 'number' },
48
- // y: { type: 'number' },
49
- // z: { type: 'number' }
50
- // }
51
- // }
52
-
53
- type T = Static<typeof T> // type T = {
54
- // x: number,
55
- // y: number,
56
- // z: number
57
- // }
58
- ```
59
-
60
-
61
- <a name="Overview"></a>
62
-
63
- ## Overview
64
-
65
- 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.
66
-
67
- 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.
68
-
69
- License MIT
70
-
71
- ## Contents
72
- - [Install](#install)
73
- - [Overview](#overview)
74
- - [Example](#Example)
75
- - [Types](#types)
76
- - [Standard](#types-standard)
77
- - [Extended](#types-extended)
78
- - [Modifiers](#types-modifiers)
79
- - [Options](#types-options)
80
- - [Reference](#types-reference)
81
- - [Recursive](#types-recursive)
82
- - [Generic](#types-generic)
83
- - [Conditional](#types-conditional)
84
- - [Unsafe](#types-unsafe)
85
- - [Guards](#types-guards)
86
- - [Strict](#types-strict)
87
- - [Values](#values)
88
- - [Create](#values-create)
89
- - [Clone](#values-clone)
90
- - [Check](#values-check)
91
- - [Cast](#values-cast)
92
- - [Equal](#values-equal)
93
- - [Hash](#values-hash)
94
- - [Diff](#values-diff)
95
- - [Patch](#values-patch)
96
- - [Errors](#values-errors)
97
- - [Pointer](#values-pointer)
98
- - [TypeCheck](#typecheck)
99
- - [TypeCompiler](#typecheck-typecompiler)
100
- - [Ajv](#typecheck-ajv)
101
- - [TypeSystem](#typecheck)
102
- - [Types](#typesystem-types)
103
- - [Formats](#typesystem-formats)
104
- - [Benchmark](#benchmark)
105
- - [Compile](#benchmark-compile)
106
- - [Validate](#benchmark-validate)
107
- - [Compression](#benchmark-compression)
108
- - [Contribute](#contribute)
109
-
110
- <a name="Example"></a>
111
-
112
- ## Example
113
-
114
- The following demonstrates TypeBox's general usage.
115
-
116
- ```typescript
117
-
118
- import { Static, Type } from '@sinclair/typebox'
119
-
120
- //--------------------------------------------------------------------------------------------
121
- //
122
- // Let's say you have the following type ...
123
- //
124
- //--------------------------------------------------------------------------------------------
125
-
126
- type T = {
127
- id: string,
128
- name: string,
129
- timestamp: number
130
- }
131
-
132
- //--------------------------------------------------------------------------------------------
133
- //
134
- // ... you can express this type in the following way.
135
- //
136
- //--------------------------------------------------------------------------------------------
137
-
138
- const T = Type.Object({ // const T = {
139
- id: Type.String(), // type: 'object',
140
- name: Type.String(), // properties: {
141
- timestamp: Type.Integer() // id: {
142
- }) // type: 'string'
143
- // },
144
- // name: {
145
- // type: 'string'
146
- // },
147
- // timestamp: {
148
- // type: 'integer'
149
- // }
150
- // },
151
- // required: [
152
- // 'id',
153
- // 'name',
154
- // 'timestamp'
155
- // ]
156
- // }
157
-
158
- //--------------------------------------------------------------------------------------------
159
- //
160
- // ... then infer back to the original static type this way.
161
- //
162
- //--------------------------------------------------------------------------------------------
163
-
164
- type T = Static<typeof T> // type T = {
165
- // id: string,
166
- // name: string,
167
- // timestamp: number
168
- // }
169
-
170
- //--------------------------------------------------------------------------------------------
171
- //
172
- // ... then use the type both as JSON schema and as a TypeScript type.
173
- //
174
- //--------------------------------------------------------------------------------------------
175
-
176
- function receive(value: T) { // ... as a Type
177
-
178
- if(JSON.validate(T, value)) { // ... as a Schema
179
-
180
- // ok...
181
- }
182
- }
183
- ```
184
-
185
- <a name='types'></a>
186
-
187
- ## Types
188
-
189
- 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.
190
-
191
- <a name='types-standard'></a>
192
-
193
- ### Standard
194
-
195
- The following table lists the Standard TypeBox types.
196
-
197
- ```typescript
198
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
199
- │ TypeBox │ TypeScript │ JSON Schema │
200
- │ │ │ │
201
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
202
- │ const T = Type.Any() │ type T = any │ const T = { } │
203
- │ │ │ │
204
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
205
- │ const T = Type.Unknown() │ type T = unknown │ const T = { } │
206
- │ │ │ │
207
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
208
- │ const T = Type.String() │ type T = string │ const T = { │
209
- │ │ │ type: 'string' │
210
- │ │ │ } │
211
- │ │ │ │
212
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
213
- │ const T = Type.Number() │ type T = number │ const T = { │
214
- │ │ │ type: 'number' │
215
- │ │ │ } │
216
- │ │ │ │
217
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
218
- │ const T = Type.Integer() │ type T = number │ const T = { │
219
- │ │ │ type: 'integer' │
220
- │ │ │ } │
221
- │ │ │ │
222
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
223
- │ const T = Type.Boolean() │ type T = boolean │ const T = { │
224
- │ │ │ type: 'boolean' │
225
- │ │ │ } │
226
- │ │ │ │
227
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
228
- │ const T = Type.Null() │ type T = null │ const T = { │
229
- │ │ │ type: 'null' │
230
- │ │ │ } │
231
- │ │ │ │
232
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
233
- │ const T = Type.RegEx(/foo/) │ type T = string │ const T = { │
234
- │ │ │ type: 'string', │
235
- │ │ │ pattern: 'foo' │
236
- │ │ │ } │
237
- │ │ │ │
238
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
239
- │ const T = Type.Literal(42) │ type T = 42 │ const T = { │
240
- │ │ │ const: 42, │
241
- │ │ │ type: 'number' │
242
- │ │ │ } │
243
- │ │ │ │
244
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
245
- │ const T = Type.Array( │ type T = number[] │ const T = { │
246
- │ Type.Number() │ │ type: 'array', │
247
- │ ) │ │ items: { │
248
- │ │ │ type: 'number' │
249
- │ │ │ } │
250
- │ │ │ } │
251
- │ │ │ │
252
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
253
- │ const T = Type.Object({ │ type T = { │ const T = { │
254
- │ x: Type.Number(), │ x: number, │ type: 'object', │
255
- │ y: Type.Number() │ y: number │ properties: { │
256
- │ }) │ } │ x: { │
257
- │ │ │ type: 'number' │
258
- │ │ │ }, │
259
- │ │ │ y: { │
260
- │ │ │ type: 'number' │
261
- │ │ │ } │
262
- │ │ │ }, │
263
- │ │ │ required: ['x', 'y'] │
264
- │ │ │ } │
265
- │ │ │ │
266
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
267
- │ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │
268
- │ Type.Number(), │ │ type: 'array', │
269
- │ Type.Number() │ │ items: [{ │
270
- │ ]) │ │ type: 'number' │
271
- │ │ │ }, { │
272
- │ │ │ type: 'number' │
273
- │ │ │ }], │
274
- │ │ │ additionalItems: false, │
275
- │ │ │ minItems: 2, │
276
- │ │ │ maxItems: 2 │
277
- │ │ │ } │
278
- │ │ │ │
279
- │ │ │ │
280
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
281
- │ enum Foo { │ enum Foo { │ const T = { │
282
- │ A, │ A, │ anyOf: [{ │
283
- │ B │ B │ type: 'number', │
284
- │ } │ } │ const: 0 │
285
- │ │ │ }, { │
286
- │ const T = Type.Enum(Foo) │ type T = Foo │ type: 'number', │
287
- │ │ │ const: 1 │
288
- │ │ │ }] │
289
- │ │ │ } │
290
- │ │ │ │
291
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
292
- │ const T = Type.KeyOf( │ type T = keyof { │ const T = { │
293
- │ Type.Object({ │ x: number, │ anyOf: [{ │
294
- │ x: Type.Number(), │ y: number │ type: 'string', │
295
- │ y: Type.Number() │ } │ const: 'x' │
296
- │ }) │ │ }, { │
297
- │ ) │ │ type: 'string', │
298
- │ │ │ const: 'y' │
299
- │ │ │ }] │
300
- │ │ │ } │
301
- │ │ │ │
302
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
303
- │ const T = Type.Union([ │ type T = string | number │ const T = { │
304
- │ Type.String(), │ │ anyOf: [{ │
305
- │ Type.Number() │ │ type: 'string' │
306
- │ ]) │ │ }, { │
307
- │ │ │ type: 'number' │
308
- │ │ │ }] │
309
- │ │ │ } │
310
- │ │ │ │
311
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
312
- │ const T = Type.Intersect([ │ type T = { │ const T = { │
313
- │ Type.Object({ │ x: number │ type: 'object', │
314
- │ x: Type.Number() │ } & { │ properties: { │
315
- │ }), │ y: number │ x: { │
316
- │ Type.Object({ │ } │ type: 'number' │
317
- │ y: Type.Number() │ │ }, │
318
- │ }) │ │ y: { │
319
- │ ]) │ │ type: 'number' │
320
- │ │ │ } │
321
- │ │ │ }, │
322
- │ │ │ required: ['x', 'y'] │
323
- │ │ │ } │
324
- │ │ │ │
325
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
326
- │ const T = Type.Never() │ type T = never │ const T = { │
327
- │ │ │ allOf: [{ │
328
- │ │ │ type: 'boolean', │
329
- │ │ │ const: false │
330
- │ │ │ }, { │
331
- │ │ │ type: 'boolean', │
332
- │ │ │ const: true │
333
- │ │ │ }] │
334
- │ │ │ } │
335
- │ │ │ │
336
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
337
- │ const T = Type.Record( │ type T = Record< │ const T = { │
338
- │ Type.String(), │ string, │ type: 'object', │
339
- │ Type.Number() │ number, │ patternProperties: { │
340
- │ ) │ > │ '^.*$': { │
341
- │ │ │ type: 'number' │
342
- │ │ │ } │
343
- │ │ │ } │
344
- │ │ │ } │
345
- │ │ │ │
346
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
347
- │ const T = Type.Partial( │ type T = Partial<{ │ const T = { │
348
- │ Type.Object({ │ x: number, │ type: 'object', │
349
- │ x: Type.Number(), │ y: number │ properties: { │
350
- │ y: Type.Number() | }> │ x: { │
351
- │ }) │ │ type: 'number' │
352
- │ ) │ │ }, │
353
- │ │ │ y: { │
354
- │ │ │ type: 'number' │
355
- │ │ │ } │
356
- │ │ │ } │
357
- │ │ │ } │
358
- │ │ │ │
359
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
360
- │ const T = Type.Required( │ type T = Required<{ │ const T = { │
361
- │ Type.Object({ │ x?: number, │ type: 'object', │
362
- │ x: Type.Optional( │ y?: number │ properties: { │
363
- │ Type.Number() | }> │ x: { │
364
- │ ), │ │ type: 'number' │
365
- │ y: Type.Optional( │ │ }, │
366
- │ Type.Number() │ │ y: { │
367
- │ ) │ │ type: 'number' │
368
- │ }) │ │ } │
369
- │ ) │ │ }, │
370
- │ │ │ required: ['x', 'y'] │
371
- │ │ │ } │
372
- │ │ │ │
373
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
374
- │ const T = Type.Pick( │ type T = Pick<{ │ const T = { │
375
- │ Type.Object({ │ x: number, │ type: 'object', │
376
- │ x: Type.Number(), │ y: number │ properties: { │
377
- │ y: Type.Number() | }, 'x'> │ x: { │
378
- │ }), ['x'] │ │ type: 'number' │
379
- │ ) │ │ } │
380
- │ │ │ }, │
381
- │ │ │ required: ['x'] │
382
- │ │ │ } │
383
- │ │ │ │
384
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
385
- │ const T = Type.Omit( │ type T = Omit<{ │ const T = { │
386
- │ Type.Object({ │ x: number, │ type: 'object', │
387
- │ x: Type.Number(), │ y: number │ properties: { │
388
- │ y: Type.Number() | }, 'x'> │ y: { │
389
- │ }), ['x'] │ │ type: 'number' │
390
- │ ) │ │ } │
391
- │ │ │ }, │
392
- │ │ │ required: ['y'] │
393
- │ │ │ } │
394
- │ │ │ │
395
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
396
- ```
397
-
398
- <a name='types-extended'></a>
399
-
400
- ### Extended
401
-
402
- TypeBox provides a set of extended types that can be used to express schematics for core JavaScript constructs and primitives. Extended types are not valid JSON Schema and will not validate using typical validation. These types however can be used to frame JSON schema and describe callable RPC interfaces that may receive JSON validated data.
403
-
404
- ```typescript
405
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
406
- │ TypeBox │ TypeScript │ Extended Schema │
407
- │ │ │ │
408
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
409
- │ const T = Type.Constructor([ │ type T = new ( │ const T = { │
410
- │ Type.String(), │ arg0: string, │ type: 'object', │
411
- │ Type.Number() │ arg1: number │ instanceOf: 'Constructor', │
412
- │ ], Type.Boolean()) │ ) => boolean │ parameters: [{ │
413
- │ │ │ type: 'string' │
414
- │ │ │ }, { │
415
- │ │ │ type: 'number' │
416
- │ │ │ }], │
417
- │ │ │ return: { │
418
- │ │ │ type: 'boolean' │
419
- │ │ │ } │
420
- │ │ │ } │
421
- │ │ │ │
422
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
423
- │ const T = Type.Function([ │ type T = ( │ const T = { │
424
- | Type.String(), │ arg0: string, │ type : 'object', │
425
- │ Type.Number() │ arg1: number │ instanceOf: 'Function', │
426
- │ ], Type.Boolean()) │ ) => boolean │ parameters: [{ │
427
- │ │ │ type: 'string' │
428
- │ │ │ }, { │
429
- │ │ │ type: 'number' │
430
- │ │ │ }], │
431
- │ │ │ return: { │
432
- │ │ │ type: 'boolean' │
433
- │ │ │ } │
434
- │ │ │ } │
435
- │ │ │ │
436
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
437
- │ const T = Type.Promise( │ type T = Promise<string> │ const T = { │
438
- │ Type.String() │ │ type: 'object', │
439
- │ ) │ │ instanceOf: 'Promise', │
440
- │ │ │ item: { │
441
- │ │ │ type: 'string' │
442
- │ │ │ } │
443
- │ │ │ } │
444
- │ │ │ │
445
- │ │ │ │
446
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
447
- │ const T = Type.Uint8Array() │ type T = Uint8Array │ const T = { │
448
- │ │ │ type: 'object', │
449
- │ │ │ instanceOf: 'Uint8Array' │
450
- │ │ │ } │
451
- │ │ │ │
452
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
453
- │ const T = Type.Date() │ type T = Date │ const T = { │
454
- │ │ │ type: 'object', │
455
- │ │ │ instanceOf: 'Date' │
456
- │ │ │ } │
457
- │ │ │ │
458
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
459
- │ const T = Type.Undefined() │ type T = undefined │ const T = { │
460
- │ │ │ type: 'null', │
461
- │ │ │ typeOf: 'Undefined' │
462
- │ │ │ } │
463
- │ │ │ │
464
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
465
- │ const T = Type.Void() │ type T = void │ const T = { │
466
- │ │ │ type: 'null' │
467
- │ │ │ typeOf: 'Void' │
468
- │ │ │ } │
469
- │ │ │ │
470
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
471
- ```
472
-
473
- <a name='types-modifiers'></a>
474
-
475
- ### Modifiers
476
-
477
- 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.
478
-
479
- ```typescript
480
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
481
- │ TypeBox │ TypeScript │ JSON Schema │
482
- │ │ │ │
483
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
484
- │ const T = Type.Object({ │ type T = { │ const T = { │
485
- │ name: Type.Optional( │ name?: string │ type: 'object', │
486
- │ Type.String() │ } │ properties: { │
487
- │ ) │ │ name: { │
488
- │ }) │ │ type: 'string' │
489
- │ │ │ } │
490
- │ │ │ } │
491
- │ │ │ } │
492
- │ │ │ │
493
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
494
- │ const T = Type.Object({ │ type T = { │ const T = { │
495
- │ name: Type.Readonly( │ readonly name: string │ type: 'object', │
496
- │ Type.String() │ } │ properties: { │
497
- │ ) │ │ name: { │
498
- │ }) │ │ type: 'string' │
499
- │ │ │ } │
500
- │ │ │ }, │
501
- │ │ │ required: ['name'] │
502
- │ │ │ } │
503
- │ │ │ │
504
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
505
- │ const T = Type.Object({ │ type T = { │ const T = { │
506
- │ name: Type.ReadonlyOptional( │ readonly name?: string │ type: 'object', │
507
- │ Type.String() │ } │ properties: { │
508
- │ ) │ │ name: { │
509
- │ }) │ │ type: 'string' │
510
- │ │ │ } │
511
- │ │ │ } │
512
- │ │ │ } │
513
- │ │ │ │
514
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
515
- ```
516
-
517
- <a name='types-options'></a>
518
-
519
- ### Options
520
-
521
- You can pass additional JSON schema options on the last argument of any given type. The following are some examples.
522
-
523
- ```typescript
524
- // string must be an email
525
- const T = Type.String({ format: 'email' })
526
-
527
- // number must be a multiple of 2
528
- const T = Type.Number({ multipleOf: 2 })
529
-
530
- // array must have at least 5 integer values
531
- const T = Type.Array(Type.Integer(), { minItems: 5 })
532
- ```
533
-
534
- <a name='types-reference'></a>
535
-
536
- ### Reference
537
-
538
- Use `Type.Ref(...)` to create referenced types. The target type must specify an `$id`.
539
-
540
- ```typescript
541
- const T = Type.String({ $id: 'T' }) // const T = {
542
- // $id: 'T',
543
- // type: 'string'
544
- // }
545
-
546
- const R = Type.Ref(T) // const R = {
547
- // $ref: 'T'
548
- // }
549
- ```
550
-
551
- <a name='types-recursive'></a>
552
-
553
- ### Recursive
554
-
555
- Use `Type.Recursive(...)` to create recursive types.
556
-
557
- ```typescript
558
- const Node = Type.Recursive(Node => Type.Object({ // const Node = {
559
- id: Type.String(), // $id: 'Node',
560
- nodes: Type.Array(Node) // type: 'object',
561
- }), { $id: 'Node' }) // properties: {
562
- // id: {
563
- // type: 'string'
564
- // },
565
- // nodes: {
566
- // type: 'array',
567
- // items: {
568
- // $ref: 'Node'
569
- // }
570
- // }
571
- // },
572
- // required: [
573
- // 'id',
574
- // 'nodes'
575
- // ]
576
- // }
577
-
578
- type Node = Static<typeof Node> // type Node = {
579
- // id: string
580
- // nodes: Node[]
581
- // }
582
-
583
- function test(node: Node) {
584
- const id = node.nodes[0].nodes[0] // id is string
585
- .nodes[0].nodes[0]
586
- .id
587
- }
588
- ```
589
-
590
- <a name='types-generic'></a>
591
-
592
- ### Generic
593
-
594
- Use functions to create generic types. The following creates a generic `Nullable<T>` type.
595
-
596
- ```typescript
597
- import { Type, Static, TSchema } from '@sinclair/typebox'
598
-
599
- const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()])
600
-
601
- const T = Nullable(Type.String()) // const T = {
602
- // anyOf: [{
603
- // type: 'string'
604
- // }, {
605
- // type: 'null'
606
- // }]
607
- // }
608
-
609
- type T = Static<typeof T> // type T = string | null
610
-
611
- const U = Nullable(Type.Number()) // const U = {
612
- // anyOf: [{
613
- // type: 'number'
614
- // }, {
615
- // type: 'null'
616
- // }]
617
- // }
618
-
619
- type U = Static<typeof U> // type U = number | null
620
- ```
621
-
622
- <a name='types-conditional'></a>
623
-
624
- ### Conditional
625
-
626
- 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.
627
-
628
- The conditional module is provided as an optional import.
629
-
630
- ```typescript
631
- import { Conditional } from '@sinclair/typebox/conditional'
632
- ```
633
- The following table shows the TypeBox mappings between TypeScript and JSON schema.
634
-
635
- ```typescript
636
- ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
637
- │ TypeBox │ TypeScript │ JSON Schema │
638
- │ │ │ │
639
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
640
- │ const T = Conditional.Extends( │ type T = │ const T = { │
641
- │ Type.String(), │ string extends number │ const: false, │
642
- │ Type.Number(), │ true : false │ type: 'boolean' │
643
- │ Type.Literal(true), │ │ } │
644
- │ Type.Literal(false) │ │ │
645
- │ ) │ │ │
646
- │ │ │ │
647
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
648
- │ const T = Conditional.Extract( │ type T = Extract< │ const T = { │
649
- │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
650
- │ Type.Literal('a'), │ 'a' | 'f' │ const: 'a' │
651
- │ Type.Literal('b'), │ > │ type: 'string' │
652
- │ Type.Literal('c') │ │ }] │
653
- │ ]), │ │ } │
654
- │ Type.Union([ │ │ │
655
- │ Type.Literal('a'), │ │ │
656
- │ Type.Literal('f') │ │ │
657
- │ ]) │ │ │
658
- │ ) │ │ │
659
- │ │ │ │
660
- ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
661
- │ const T = Conditional.Exclude( │ type T = Exclude< │ const T = { │
662
- │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
663
- │ Type.Literal('a'), │ 'a' │ const: 'b', │
664
- │ Type.Literal('b'), │ > │ type: 'string' │
665
- │ Type.Literal('c') │ │ }, { │
666
- │ ]), │ │ const: 'c', │
667
- │ Type.Union([ │ │ type: 'string' │
668
- │ Type.Literal('a') │ │ }] │
669
- │ ]) │ │ } │
670
- │ ) │ │ │
671
- │ │ │ │
672
- └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
673
- ```
674
-
675
- <a name='types-unsafe'></a>
676
-
677
- ### Unsafe
678
-
679
- Use `Type.Unsafe(...)` to create custom schemas with user defined inference rules.
680
-
681
- ```typescript
682
- const T = Type.Unsafe<string>({ type: 'number' }) // const T = {
683
- // type: 'number'
684
- // }
685
-
686
- type T = Static<typeof T> // type T = string
687
- ```
688
-
689
- 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.
690
-
691
- ```typescript
692
- import { Type, Static, TSchema } from '@sinclair/typebox'
693
-
694
- //--------------------------------------------------------------------------------------------
695
- //
696
- // Nullable<T>
697
- //
698
- //--------------------------------------------------------------------------------------------
699
-
700
- function Nullable<T extends TSchema>(schema: T) {
701
- return Type.Unsafe<Static<T> | null>({ ...schema, nullable: true })
702
- }
703
-
704
- const T = Nullable(Type.String()) // const T = {
705
- // type: 'string',
706
- // nullable: true
707
- // }
708
-
709
- type T = Static<typeof T> // type T = string | null
710
-
711
-
712
- //--------------------------------------------------------------------------------------------
713
- //
714
- // StringEnum<string[]>
715
- //
716
- //--------------------------------------------------------------------------------------------
717
-
718
- function StringEnum<T extends string[]>(values: [...T]) {
719
- return Type.Unsafe<T[number]>({ type: 'string', enum: values })
720
- }
721
-
722
- const T = StringEnum(['A', 'B', 'C']) // const T = {
723
- // enum: ['A', 'B', 'C']
724
- // }
725
-
726
- type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
727
- ```
728
-
729
- <a name='types-guards'></a>
730
-
731
- ### Guards
732
-
733
- Use the guard module to test if values are TypeBox types.
734
-
735
- ```typescript
736
- import { TypeGuard } from '@sinclair/typebox/guard'
737
-
738
- const T = Type.String()
739
-
740
- if(TypeGuard.TString(T)) {
741
-
742
- // T is TString
743
- }
744
- ```
745
-
746
- <a name='types-strict'></a>
747
-
748
- ### Strict
749
-
750
- 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.
751
-
752
- ```typescript
753
- const T = Type.Object({ // const T = {
754
- name: Type.Optional(Type.String()) // [Kind]: 'Object',
755
- }) // type: 'object',
756
- // properties: {
757
- // name: {
758
- // [Kind]: 'String',
759
- // type: 'string',
760
- // [Modifier]: 'Optional'
761
- // }
762
- // }
763
- // }
764
-
765
- const U = Type.Strict(T) // const U = {
766
- // type: 'object',
767
- // properties: {
768
- // name: {
769
- // type: 'string'
770
- // }
771
- // }
772
- // }
773
- ```
774
-
775
- <a name='values'></a>
776
-
777
- ## Values
778
-
779
- 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.
780
-
781
- ```typescript
782
- import { Value } from '@sinclair/typebox/value'
783
- ```
784
-
785
- <a name='values-create'></a>
786
-
787
- ### Create
788
-
789
- Use the Create function to create a value from a TypeBox type. TypeBox will use default values if specified.
790
-
791
- ```typescript
792
- const T = Type.Object({ x: Type.Number(), y: Type.Number({ default: 42 }) })
793
-
794
- const A = Value.Create(T) // const A = { x: 0, y: 42 }
795
- ```
796
-
797
- <a name='values-clone'></a>
798
-
799
- ### Clone
800
-
801
- Use the Clone function to deeply clone a value
802
-
803
- ```typescript
804
- const A = Value.Clone({ x: 1, y: 2, z: 3 }) // const A = { x: 1, y: 2, z: 3 }
805
- ```
806
-
807
- <a name='values-check'></a>
808
-
809
- ### Check
810
-
811
- Use the Check function to type check a value
812
-
813
- ```typescript
814
- const T = Type.Object({ x: Type.Number() })
815
-
816
- const R = Value.Check(T, { x: 1 }) // const R = true
817
- ```
818
-
819
- <a name='values-cast'></a>
820
-
821
- ### Cast
822
-
823
- 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.
824
-
825
- ```typescript
826
- const T = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false })
827
-
828
- const X = Value.Cast(T, null) // const X = { x: 0, y: 0 }
829
-
830
- const Y = Value.Cast(T, { x: 1 }) // const Y = { x: 1, y: 0 }
831
-
832
- const Z = Value.Cast(T, { x: 1, y: 2, z: 3 }) // const Z = { x: 1, y: 2 }
833
- ```
834
-
835
- <a name='values-equal'></a>
836
-
837
- ### Equal
838
-
839
- Use the Equal function to deeply check for value equality.
840
-
841
- ```typescript
842
- const R = Value.Equal( // const R = true
843
- { x: 1, y: 2, z: 3 },
844
- { x: 1, y: 2, z: 3 }
845
- )
846
- ```
847
-
848
- <a name='values-hash'></a>
849
-
850
- ### Hash
851
-
852
- Use the Hash function to create a [FNV1A-64](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) non cryptographic hash of a value.
853
-
854
- ```typescript
855
- const A = Value.Hash({ x: 1, y: 2, z: 3 }) // const A = 2910466848807138541n
856
-
857
- const B = Value.Hash({ x: 1, y: 4, z: 3 }) // const B = 1418369778807423581n
858
- ```
859
-
860
- <a name='values-diff'></a>
861
-
862
- ### Diff
863
-
864
- Use the Diff function to produce a sequence of edits to transform one value into another.
865
-
866
- ```typescript
867
- const E = Value.Diff( // const E = [
868
- { x: 1, y: 2, z: 3 }, // { type: 'update', path: '/y', value: 4 },
869
- { y: 4, z: 5, w: 6 } // { type: 'update', path: '/z', value: 5 },
870
- ) // { type: 'insert', path: '/w', value: 6 },
871
- // { type: 'delete', path: '/x' }
872
- // ]
873
- ```
874
-
875
- <a name='values-patch'></a>
876
-
877
- ### Patch
878
-
879
- Use the Patch function to apply edits
880
-
881
- ```typescript
882
- const A = { x: 1, y: 2 }
883
-
884
- const B = { x: 3 }
885
-
886
- const E = Value.Diff(A, B) // const E = [
887
- // { type: 'update', path: '/x', value: 3 },
888
- // { type: 'delete', path: '/y' }
889
- // ]
890
-
891
- const C = Value.Patch<typeof B>(A, E) // const C = { x: 3 }
892
- ```
893
-
894
-
895
- <a name='values-errors'></a>
896
-
897
- ### Errors
898
-
899
- Use the Errors function enumerate validation errors.
900
-
901
- ```typescript
902
- const T = Type.Object({ x: Type.Number(), y: Type.Number() })
903
-
904
- const R = [...Value.Errors(T, { x: '42' })] // const R = [{
905
- // schema: { type: 'number' },
906
- // path: '/x',
907
- // value: '42',
908
- // message: 'Expected number'
909
- // }, {
910
- // schema: { type: 'number' },
911
- // path: '/y',
912
- // value: undefined,
913
- // message: 'Expected number'
914
- // }]
915
- ```
916
-
917
- <a name='values-pointer'></a>
918
-
919
- ### Pointer
920
-
921
- Use ValuePointer to perform mutable updates on existing values using [RFC6901](https://www.rfc-editor.org/rfc/rfc6901) Json Pointers.
922
-
923
- ```typescript
924
- import { ValuePointer } from '@sinclair/typebox/value'
925
-
926
- const A = { x: 0, y: 0, z: 0 }
927
-
928
- ValuePointer.Set(A, '/x', 1) // const A = { x: 1, y: 0, z: 0 }
929
- ValuePointer.Set(A, '/y', 1) // const A = { x: 1, y: 1, z: 0 }
930
- ValuePointer.Set(A, '/z', 1) // const A = { x: 1, y: 1, z: 1 }
931
- ```
932
- <a name='typecheck'></a>
933
-
934
- ## TypeCheck
935
-
936
- TypeBox targets JSON Schema Draft 6 and is built and tested against the Ajv JSON Schema validator for standards compliance. TypeBox also includes an optional built-in TypeCompiler that can provide improved compilation and validation performance specifically for TypeBox types only.
937
-
938
- The following sections detail using these validators.
939
-
940
- <a name='typecheck-typecompiler'></a>
941
-
942
- ### TypeCompiler
943
-
944
- TypeBox includes an 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.
945
-
946
- The compiler module is provided as an optional import.
947
-
948
- ```typescript
949
- import { TypeCompiler } from '@sinclair/typebox/compiler'
950
- ```
951
-
952
- Use the `Compile(...)` function to compile a type.
953
-
954
- ```typescript
955
- const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
956
- x: Type.Number(), // x: TNumber;
957
- y: Type.Number(), // y: TNumber;
958
- z: Type.Number() // z: TNumber;
959
- })) // }>>
960
-
961
- const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true
962
- ```
963
-
964
- Validation errors can be read with the `Errors(...)` function.
965
-
966
- ```typescript
967
- const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
968
- x: Type.Number(), // x: TNumber;
969
- y: Type.Number(), // y: TNumber;
970
- z: Type.Number() // z: TNumber;
971
- })) // }>>
972
-
973
- const value = { }
974
-
975
- const errors = [...C.Errors(value)] // const errors = [{
976
- // schema: { type: 'number' },
977
- // path: '/x',
978
- // value: undefined,
979
- // message: 'Expected number'
980
- // }, {
981
- // schema: { type: 'number' },
982
- // path: '/y',
983
- // value: undefined,
984
- // message: 'Expected number'
985
- // }, {
986
- // schema: { type: 'number' },
987
- // path: '/z',
988
- // value: undefined,
989
- // message: 'Expected number'
990
- // }]
991
- ```
992
-
993
- Compiled routines can be inspected with the `.Code()` function.
994
-
995
- ```typescript
996
- const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString>
997
-
998
- console.log(C.Code()) // return function check(value) {
999
- // return (
1000
- // (typeof value === 'string')
1001
- // )
1002
- // }
1003
- ```
1004
-
1005
- <a name='typecheck-ajv'></a>
1006
-
1007
- ### Ajv
1008
-
1009
- The following are the recommended configurations to support both the [Standard](#standard) and [Extended](#extended) type sets provided by TypeBox. For schema portability and publishing to remote systems, it is recommended to use the Standard type set only.
1010
-
1011
- ```bash
1012
- $ npm install ajv ajv-formats --save
1013
- ```
1014
-
1015
- <details>
1016
-
1017
- <summary>
1018
- <strong>Standard Ajv Configuration</strong>
1019
- <p>Expand for Standard Type Set Configuration</p>
1020
- </summary>
1021
-
1022
- ```typescript
1023
- import { Type } from '@sinclair/typebox'
1024
- import addFormats from 'ajv-formats'
1025
- import Ajv from 'ajv'
1026
-
1027
- export function createAjv() {
1028
- return addFormats(new Ajv({}), [
1029
- 'date-time',
1030
- 'time',
1031
- 'date',
1032
- 'email',
1033
- 'hostname',
1034
- 'ipv4',
1035
- 'ipv6',
1036
- 'uri',
1037
- 'uri-reference',
1038
- 'uuid',
1039
- 'uri-template',
1040
- 'json-pointer',
1041
- 'relative-json-pointer',
1042
- 'regex'
1043
- ])
1044
- }
1045
-
1046
- const ajv = createAjv()
1047
-
1048
- const R = ajv.validate(Type.Object({ // const R = true
1049
- x: Type.Number(),
1050
- y: Type.Number(),
1051
- z: Type.Number()
1052
- }), { x: 1, y: 2, z: 3 })
1053
- ```
1054
-
1055
- </details>
1056
-
1057
- <details>
1058
-
1059
- <summary>
1060
- <strong>Extended Ajv Configuration</strong>
1061
- <p>Expand for Extended Type Set Configuration</p>
1062
- </summary>
1063
-
1064
- ```typescript
1065
- import { TypeGuard } from '@sinclair/typebox/guard'
1066
- import { Value } from '@sinclair/typebox/value'
1067
- import { Type } from '@sinclair/typebox'
1068
- import addFormats from 'ajv-formats'
1069
- import Ajv from 'ajv'
1070
-
1071
- function schemaOf(schemaOf: string, value: unknown, schema: unknown) {
1072
- switch (schemaOf) {
1073
- case 'Constructor':
1074
- return TypeGuard.TConstructor(schema) && Value.Check(schema, value) // not supported
1075
- case 'Function':
1076
- return TypeGuard.TFunction(schema) && Value.Check(schema, value) // not supported
1077
- case 'Date':
1078
- return TypeGuard.TDate(schema) && Value.Check(schema, value)
1079
- case 'Promise':
1080
- return TypeGuard.TPromise(schema) && Value.Check(schema, value) // not supported
1081
- case 'Uint8Array':
1082
- return TypeGuard.TUint8Array(schema) && Value.Check(schema, value)
1083
- case 'Undefined':
1084
- return TypeGuard.TUndefined(schema) && Value.Check(schema, value) // not supported
1085
- case 'Void':
1086
- return TypeGuard.TVoid(schema) && Value.Check(schema, value)
1087
- default:
1088
- return false
1089
- }
1090
- }
1091
-
1092
- export function createAjv() {
1093
- return addFormats(new Ajv({}), [
1094
- 'date-time',
1095
- 'time',
1096
- 'date',
1097
- 'email',
1098
- 'hostname',
1099
- 'ipv4',
1100
- 'ipv6',
1101
- 'uri',
1102
- 'uri-reference',
1103
- 'uuid',
1104
- 'uri-template',
1105
- 'json-pointer',
1106
- 'relative-json-pointer',
1107
- 'regex'
1108
- ])
1109
- .addKeyword({ type: 'object', keyword: 'instanceOf', validate: schemaOf })
1110
- .addKeyword({ type: 'null', keyword: 'typeOf', validate: schemaOf })
1111
- .addKeyword('exclusiveMinimumTimestamp')
1112
- .addKeyword('exclusiveMaximumTimestamp')
1113
- .addKeyword('minimumTimestamp')
1114
- .addKeyword('maximumTimestamp')
1115
- .addKeyword('minByteLength')
1116
- .addKeyword('maxByteLength')
1117
- }
1118
-
1119
- const ajv = createAjv()
1120
-
1121
- const R = ajv.validate(Type.Object({ // const R = true
1122
- buffer: Type.Uint8Array(),
1123
- date: Type.Date(),
1124
- void: Type.Void()
1125
- }), {
1126
- buffer: new Uint8Array(),
1127
- date: new Date(),
1128
- void: null
1129
- })
1130
- ```
1131
-
1132
- </details>
1133
-
1134
-
1135
- <a name='typesystem'></a>
1136
-
1137
- ## TypeSystem
1138
-
1139
- TypeBox provides an extensible TypeSystem module that enables developers to register additional types above and beyond the standard or extended type set. This module also allows developers to define custom string formats as well as override certain type checking behaviours.
1140
-
1141
- The TypeSystem module is provided as an optional import.
1142
-
1143
- ```typescript
1144
- import { TypeSystem } from '@sinclair/typebox/system'
1145
- ```
1146
-
1147
- <a name='typesystem-types'></a>
1148
-
1149
- ### Types
1150
-
1151
- Use the `CreateType(...)` function to specify and return a custom type. This function will return a type factory function that can be used to construct the type. The following creates and registers a BigNumber type which will statically infer as `bigint`.
1152
-
1153
- ```typescript
1154
- //--------------------------------------------------------------------------------------------
1155
- //
1156
- // Use TypeSystem.CreateType(...) to define and return a type factory function
1157
- //
1158
- //--------------------------------------------------------------------------------------------
1159
-
1160
- type BigNumberOptions = { minimum?: bigint; maximum?: bigint }
1161
-
1162
- const BigNumber = TypeSystem.CreateType<bigint, BigNumberOptions>(
1163
- 'BigNumber',
1164
- (options, value) => {
1165
- if (typeof value !== 'bigint') return false
1166
- if (options.maximum !== undefined && value > options.maximum) return false
1167
- if (options.minimum !== undefined && value < options.minimum) return false
1168
- return true
1169
- }
1170
- )
1171
-
1172
- //--------------------------------------------------------------------------------------------
1173
- //
1174
- // Use the custom type like any other type
1175
- //
1176
- //--------------------------------------------------------------------------------------------
1177
-
1178
- const T = BigNumber({ minimum: 10n, maximum: 20n }) // const T = {
1179
- // minimum: 10n,
1180
- // maximum: 20n,
1181
- // [Symbol(TypeBox.Kind)]: 'BigNumber'
1182
- // }
1183
-
1184
- const C = TypeCompiler.Compile(T)
1185
- const X = C.Check(15n) // const X = true
1186
- const Y = C.Check(5n) // const Y = false
1187
- const Z = C.Check(25n) // const Z = false
1188
- ```
1189
-
1190
- <a name='typesystem-formats'></a>
1191
-
1192
- ### Formats
1193
-
1194
- Use the `CreateFormat(...)` function to specify user defined string formats. The following creates a custom string format that checks for lowercase.
1195
-
1196
- ```typescript
1197
- //--------------------------------------------------------------------------------------------
1198
- //
1199
- // Use TypeSystem.CreateFormat(...) to define a custom string format
1200
- //
1201
- //--------------------------------------------------------------------------------------------
1202
-
1203
- TypeSystem.CreateFormat('lowercase', value => value === value.toLowerCase())
1204
-
1205
- //--------------------------------------------------------------------------------------------
1206
- //
1207
- // Use the format by creating string types with the 'format' option
1208
- //
1209
- //--------------------------------------------------------------------------------------------
1210
-
1211
- const T = Type.String({ format: 'lowercase' })
1212
-
1213
- const A = Value.Check(T, 'action') // const A = true
1214
-
1215
- const B = Value.Check(T, 'ACTION') // const B = false
1216
- ```
1217
-
1218
- <a name='benchmark'></a>
1219
-
1220
- ## Benchmark
1221
-
1222
- This project maintains a set of benchmarks that measure Ajv, Value and TypeCompiler compilation and validation performance. These benchmarks can be run locally by cloning this repository and running `npm run benchmark`. The results below show for Ajv version 8.11.2.
1223
-
1224
- For additional comparative benchmarks, please refer to [typescript-runtime-type-benchmarks](https://moltar.github.io/typescript-runtime-type-benchmarks/).
1225
-
1226
- <a name='benchmark-compile'></a>
1227
-
1228
- ### Compile
1229
-
1230
- 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).
1231
-
1232
- ```typescript
1233
- ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┐
1234
- │ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │
1235
- ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┤
1236
- │ Number │ 2000 │ ' 418 ms' │ ' 14 ms' │ ' 29.86 x' │
1237
- │ String │ 2000 │ ' 331 ms' ' 12 ms' ' 27.58 x'
1238
- │ Boolean │ 2000 │ ' 290 ms' │ ' 13 ms' │ ' 22.31 x' │
1239
- │ Null │ 2000 │ ' 253 ms' │ ' 8 ms' │ ' 31.63 x' │
1240
- │ RegEx │ 2000 │ ' 481 ms' │ ' 18 ms' │ ' 26.72 x' │
1241
- │ ObjectA │ 2000 │ ' 2675 ms' │ ' 54 ms' │ ' 49.54 x' │
1242
- │ ObjectB │ 2000 │ ' 2849 ms' │ ' 39 ms' │ ' 73.05 x' │
1243
- │ Tuple │ 2000 │ ' 1224 ms' │ ' 22 ms' │ ' 55.64 x' │
1244
- │ Union │ 2000 │ ' 1225 ms' │ ' 26 ms' │ ' 47.12 x' │
1245
- │ Vector4 │ 2000 │ ' 1777 ms' │ ' 24 ms' │ ' 74.04 x' │
1246
- │ Matrix4 │ 2000 │ ' 825 ms' │ ' 12 ms' │ ' 68.75 x' │
1247
- │ Literal_String │ 2000 │ ' 345 ms' │ ' 9 ms' │ ' 38.33 x' │
1248
- │ Literal_Number │ 2000 │ ' 363 ms' │ ' 7 ms' │ ' 51.86 x' │
1249
- │ Literal_Boolean │ 2000 │ ' 358 ms' │ ' 6 ms' │ ' 59.67 x' │
1250
- │ Array_Number │ 2000 │ ' 687 ms' │ ' 8 ms' │ ' 85.88 x' │
1251
- │ Array_String │ 2000 │ ' 726 ms' │ ' 8 ms' │ ' 90.75 x' │
1252
- │ Array_Boolean │ 2000 │ ' 703 ms' │ ' 8 ms' │ ' 87.88 x' │
1253
- │ Array_ObjectA │ 2000 │ ' 3686 ms' │ ' 40 ms' │ ' 92.15 x' │
1254
- │ Array_ObjectB │ 2000 │ ' 3821 ms' │ ' 40 ms' │ ' 95.53 x' │
1255
- │ Array_Tuple │ 2000 │ ' 2070 ms' │ ' 17 ms' │ ' 121.76 x' │
1256
- │ Array_Union │ 2000 │ ' 1503 ms' │ ' 21 ms' │ ' 71.57 x' │
1257
- │ Array_Vector4 │ 2000 │ ' 2185 ms' │ ' 21 ms' │ ' 104.05 x' │
1258
- │ Array_Matrix4 │ 2000 │ ' 1502 ms' │ ' 16 ms' │ ' 93.88 x' │
1259
- └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┘
1260
- ```
1261
-
1262
- <a name='benchmark-validate'></a>
1263
-
1264
- ### Validate
1265
-
1266
- 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).
1267
-
1268
- ```typescript
1269
- ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
1270
- │ (index) │ Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │
1271
- ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
1272
- │ Number │ 1000000 │ ' 28 ms' │ ' 6 ms' │ ' 6 ms' │ ' 1.00 x' │
1273
- │ String │ 1000000 │ ' 25 ms' │ ' 23 ms' │ ' 11 ms' │ ' 2.09 x' │
1274
- │ Boolean │ 1000000 │ ' 24 ms' │ ' 21 ms' │ ' 11 ms' │ ' 1.91 x' │
1275
- │ Null │ 1000000 │ ' 25 ms' │ ' 22 ms' │ ' 10 ms' │ ' 2.20 x' │
1276
- │ RegEx │ 1000000 │ ' 164 ms' │ ' 53 ms' │ ' 37 ms' │ ' 1.43 x' │
1277
- │ ObjectA │ 1000000 │ ' 593 ms' │ ' 47 ms' │ ' 25 ms' │ ' 1.88 x' │
1278
- │ ObjectB │ 1000000 │ ' 1053 ms' │ ' 54 ms' │ ' 40 ms' │ ' 1.35 x' │
1279
- │ Tuple │ 1000000 │ ' 129 ms' │ ' 25 ms' │ ' 16 ms' │ ' 1.56 x' │
1280
- │ Union │ 1000000 │ ' 334 ms' │ ' 25 ms' │ ' 16 ms' │ ' 1.56 x' │
1281
- │ Recursive │ 1000000 │ ' 3127 ms' │ ' 424 ms' │ ' 98 ms' │ ' 4.33 x' │
1282
- │ Vector4 │ 1000000 │ ' 152 ms' │ ' 24 ms' │ ' 12 ms' │ ' 2.00 x' │
1283
- │ Matrix4 │ 1000000 │ ' 593 ms' │ ' 41 ms' │ ' 27 ms' │ ' 1.52 x' │
1284
- │ Literal_String │ 1000000 │ ' 48 ms' │ ' 20 ms' │ ' 11 ms' │ ' 1.82 x' │
1285
- │ Literal_Number │ 1000000 │ ' 47 ms' │ ' 22 ms' │ ' 10 ms' │ ' 2.20 x' │
1286
- │ Literal_Boolean │ 1000000 │ ' 48 ms' │ ' 21 ms' │ ' 11 ms' │ ' 1.91 x' │
1287
- │ Array_Number │ 1000000 │ ' 495 ms' │ ' 32 ms' │ ' 21 ms' │ ' 1.52 x' │
1288
- │ Array_String │ 1000000 │ ' 481 ms' │ ' 31 ms' │ ' 21 ms' │ ' 1.48 x' │
1289
- │ Array_Boolean │ 1000000 │ ' 446 ms' │ ' 32 ms' │ ' 27 ms' │ ' 1.19 x' │
1290
- │ Array_ObjectA │ 1000000 │ ' 14314 ms' │ ' 2341 ms' │ ' 1969 ms' │ ' 1.19 x' │
1291
- │ Array_ObjectB │ 1000000 │ ' 16883 ms' │ ' 2661 ms' │ ' 2606 ms' │ ' 1.02 x' │
1292
- │ Array_Tuple │ 1000000 │ ' 1834 ms' │ ' 98 ms' │ ' 77 ms' │ ' 1.27 x' │
1293
- │ Array_Union │ 1000000 │ ' 4960 ms' │ ' 240 ms' │ ' 87 ms' │ ' 2.76 x' │
1294
- │ Array_Recursive │ 1000000 │ ' 56273 ms' │ ' 7118 ms' │ ' 1122 ms' │ ' 6.34 x' │
1295
- │ Array_Vector4 │ 1000000 │ ' 2498 ms' │ ' 99 ms' │ ' 48 ms' │ ' 2.06 x' │
1296
- │ Array_Matrix4 │ 1000000 │ ' 12487 ms' │ ' 383 ms' │ ' 246 ms' │ ' 1.56 x' │
1297
- └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
1298
- ```
1299
-
1300
- <a name='benchmark-compression'></a>
1301
-
1302
- ### Compression
1303
-
1304
- The following table lists esbuild compiled and minified sizes for each TypeBox module.
1305
-
1306
- ```typescript
1307
- ┌──────────────────────┬────────────┬────────────┬─────────────┐
1308
- │ (index) │ Compiled │ Minified │ Compression │
1309
- ├──────────────────────┼────────────┼────────────┼─────────────┤
1310
- │ typebox/compiler │ ' 64 kb' │ ' 31 kb' │ '2.02 x' │
1311
- │ typebox/conditional │ ' 45 kb' │ ' 18 kb' │ '2.44 x' │
1312
- │ typebox/custom │ ' 0 kb' │ ' 0 kb' │ '2.61 x' │
1313
- │ typebox/format │ ' 0 kb' │ ' 0 kb' │ '2.66 x' │
1314
- │ typebox/guard │ ' 23 kb' │ ' 11 kb' │ '2.07 x' │
1315
- │ typebox/hash │ ' 4 kb' │ ' 1 kb' │ '2.30 x' │
1316
- │ typebox/value │ ' 89 kb' │ ' 41 kb' │ '2.15 x' │
1317
- │ typebox │ ' 12 kb' │ ' 6 kb' │ '1.89 x' │
1318
- └──────────────────────┴────────────┴────────────┴─────────────┘
1319
- ```
1320
-
1321
- <a name='contribute'></a>
1322
-
1323
- ## Contribute
1324
-
1325
- 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
+ #### Npm
23
+ ```bash
24
+ $ npm install @sinclair/typebox --save
25
+ ```
26
+
27
+ #### Deno
28
+ ```typescript
29
+ import { Static, Type } from 'npm:@sinclair/typebox'
30
+ ```
31
+
32
+ #### Esm
33
+
34
+ ```typescript
35
+ import { Static, Type } from 'https://esm.sh/@sinclair/typebox'
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```typescript
41
+ import { Static, Type } from '@sinclair/typebox'
42
+
43
+ const T = Type.Object({ // const T = {
44
+ x: Type.Number(), // type: 'object',
45
+ y: Type.Number(), // required: ['x', 'y', 'z'],
46
+ z: Type.Number() // properties: {
47
+ }) // x: { type: 'number' },
48
+ // y: { type: 'number' },
49
+ // z: { type: 'number' }
50
+ // }
51
+ // }
52
+
53
+ type T = Static<typeof T> // type T = {
54
+ // x: number,
55
+ // y: number,
56
+ // z: number
57
+ // }
58
+ ```
59
+
60
+
61
+ <a name="Overview"></a>
62
+
63
+ ## Overview
64
+
65
+ 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.
66
+
67
+ This library is designed to enable JSON schema to compose with the same flexibility as TypeScript's type system. It can be used either as a simple tool to build up complex schemas or integrated into REST and RPC services to help validate data received over the wire.
68
+
69
+ License MIT
70
+
71
+ ## Contents
72
+ - [Install](#install)
73
+ - [Overview](#overview)
74
+ - [Example](#Example)
75
+ - [Types](#types)
76
+ - [Standard](#types-standard)
77
+ - [Extended](#types-extended)
78
+ - [Modifiers](#types-modifiers)
79
+ - [Options](#types-options)
80
+ - [Reference](#types-reference)
81
+ - [Recursive](#types-recursive)
82
+ - [Generic](#types-generic)
83
+ - [Conditional](#types-conditional)
84
+ - [Unsafe](#types-unsafe)
85
+ - [Guards](#types-guards)
86
+ - [Strict](#types-strict)
87
+ - [Values](#values)
88
+ - [Create](#values-create)
89
+ - [Clone](#values-clone)
90
+ - [Check](#values-check)
91
+ - [Cast](#values-cast)
92
+ - [Equal](#values-equal)
93
+ - [Hash](#values-hash)
94
+ - [Diff](#values-diff)
95
+ - [Patch](#values-patch)
96
+ - [Errors](#values-errors)
97
+ - [Pointer](#values-pointer)
98
+ - [TypeCheck](#typecheck)
99
+ - [Ajv](#typecheck-ajv)
100
+ - [TypeCompiler](#typecheck-typecompiler)
101
+ - [TypeSystem](#typecheck)
102
+ - [Types](#typesystem-types)
103
+ - [Formats](#typesystem-formats)
104
+ - [Benchmark](#benchmark)
105
+ - [Compile](#benchmark-compile)
106
+ - [Validate](#benchmark-validate)
107
+ - [Compression](#benchmark-compression)
108
+ - [Contribute](#contribute)
109
+
110
+ <a name="Example"></a>
111
+
112
+ ## Example
113
+
114
+ The following demonstrates TypeBox's general usage.
115
+
116
+ ```typescript
117
+
118
+ import { Static, Type } from '@sinclair/typebox'
119
+
120
+ //--------------------------------------------------------------------------------------------
121
+ //
122
+ // Let's say you have the following type ...
123
+ //
124
+ //--------------------------------------------------------------------------------------------
125
+
126
+ type T = {
127
+ id: string,
128
+ name: string,
129
+ timestamp: number
130
+ }
131
+
132
+ //--------------------------------------------------------------------------------------------
133
+ //
134
+ // ... you can express this type in the following way.
135
+ //
136
+ //--------------------------------------------------------------------------------------------
137
+
138
+ const T = Type.Object({ // const T = {
139
+ id: Type.String(), // type: 'object',
140
+ name: Type.String(), // properties: {
141
+ timestamp: Type.Integer() // id: {
142
+ }) // type: 'string'
143
+ // },
144
+ // name: {
145
+ // type: 'string'
146
+ // },
147
+ // timestamp: {
148
+ // type: 'integer'
149
+ // }
150
+ // },
151
+ // required: [
152
+ // 'id',
153
+ // 'name',
154
+ // 'timestamp'
155
+ // ]
156
+ // }
157
+
158
+ //--------------------------------------------------------------------------------------------
159
+ //
160
+ // ... then infer back to the original static type this way.
161
+ //
162
+ //--------------------------------------------------------------------------------------------
163
+
164
+ type T = Static<typeof T> // type T = {
165
+ // id: string,
166
+ // name: string,
167
+ // timestamp: number
168
+ // }
169
+
170
+ //--------------------------------------------------------------------------------------------
171
+ //
172
+ // ... then use the type both as JSON schema and as a TypeScript type.
173
+ //
174
+ //--------------------------------------------------------------------------------------------
175
+
176
+ function receive(value: T) { // ... as a Type
177
+
178
+ if(JSON.validate(T, value)) { // ... as a Schema
179
+
180
+ // ok...
181
+ }
182
+ }
183
+ ```
184
+
185
+ <a name='types'></a>
186
+
187
+ ## Types
188
+
189
+ 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.
190
+
191
+ <a name='types-standard'></a>
192
+
193
+ ### Standard
194
+
195
+ The following table lists the Standard TypeBox types.
196
+
197
+ ```typescript
198
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
199
+ │ TypeBox │ TypeScript │ JSON Schema │
200
+ │ │ │ │
201
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
202
+ │ const T = Type.Any() │ type T = any │ const T = { } │
203
+ │ │ │ │
204
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
205
+ │ const T = Type.Unknown() │ type T = unknown │ const T = { } │
206
+ │ │ │ │
207
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
208
+ │ const T = Type.String() │ type T = string │ const T = { │
209
+ │ │ │ type: 'string' │
210
+ │ │ │ } │
211
+ │ │ │ │
212
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
213
+ │ const T = Type.Number() │ type T = number │ const T = { │
214
+ │ │ │ type: 'number' │
215
+ │ │ │ } │
216
+ │ │ │ │
217
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
218
+ │ const T = Type.Integer() │ type T = number │ const T = { │
219
+ │ │ │ type: 'integer' │
220
+ │ │ │ } │
221
+ │ │ │ │
222
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
223
+ │ const T = Type.Boolean() │ type T = boolean │ const T = { │
224
+ │ │ │ type: 'boolean' │
225
+ │ │ │ } │
226
+ │ │ │ │
227
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
228
+ │ const T = Type.Null() │ type T = null │ const T = { │
229
+ │ │ │ type: 'null' │
230
+ │ │ │ } │
231
+ │ │ │ │
232
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
233
+ │ const T = Type.RegEx(/foo/) │ type T = string │ const T = { │
234
+ │ │ │ type: 'string', │
235
+ │ │ │ pattern: 'foo' │
236
+ │ │ │ } │
237
+ │ │ │ │
238
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
239
+ │ const T = Type.Literal(42) │ type T = 42 │ const T = { │
240
+ │ │ │ const: 42, │
241
+ │ │ │ type: 'number' │
242
+ │ │ │ } │
243
+ │ │ │ │
244
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
245
+ │ const T = Type.Array( │ type T = number[] │ const T = { │
246
+ │ Type.Number() │ │ type: 'array', │
247
+ │ ) │ │ items: { │
248
+ │ │ │ type: 'number' │
249
+ │ │ │ } │
250
+ │ │ │ } │
251
+ │ │ │ │
252
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
253
+ │ const T = Type.Object({ │ type T = { │ const T = { │
254
+ │ x: Type.Number(), │ x: number, │ type: 'object', │
255
+ │ y: Type.Number() │ y: number │ properties: { │
256
+ │ }) │ } │ x: { │
257
+ │ │ │ type: 'number' │
258
+ │ │ │ }, │
259
+ │ │ │ y: { │
260
+ │ │ │ type: 'number' │
261
+ │ │ │ } │
262
+ │ │ │ }, │
263
+ │ │ │ required: ['x', 'y'] │
264
+ │ │ │ } │
265
+ │ │ │ │
266
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
267
+ │ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │
268
+ │ Type.Number(), │ │ type: 'array', │
269
+ │ Type.Number() │ │ items: [{ │
270
+ │ ]) │ │ type: 'number' │
271
+ │ │ │ }, { │
272
+ │ │ │ type: 'number' │
273
+ │ │ │ }], │
274
+ │ │ │ additionalItems: false, │
275
+ │ │ │ minItems: 2, │
276
+ │ │ │ maxItems: 2 │
277
+ │ │ │ } │
278
+ │ │ │ │
279
+ │ │ │ │
280
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
281
+ │ enum Foo { │ enum Foo { │ const T = { │
282
+ │ A, │ A, │ anyOf: [{ │
283
+ │ B │ B │ type: 'number', │
284
+ │ } │ } │ const: 0 │
285
+ │ │ │ }, { │
286
+ │ const T = Type.Enum(Foo) │ type T = Foo │ type: 'number', │
287
+ │ │ │ const: 1 │
288
+ │ │ │ }] │
289
+ │ │ │ } │
290
+ │ │ │ │
291
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
292
+ │ const T = Type.KeyOf( │ type T = keyof { │ const T = { │
293
+ │ Type.Object({ │ x: number, │ anyOf: [{ │
294
+ │ x: Type.Number(), │ y: number │ type: 'string', │
295
+ │ y: Type.Number() │ } │ const: 'x' │
296
+ │ }) │ │ }, { │
297
+ │ ) │ │ type: 'string', │
298
+ │ │ │ const: 'y' │
299
+ │ │ │ }] │
300
+ │ │ │ } │
301
+ │ │ │ │
302
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
303
+ │ const T = Type.Union([ │ type T = string | number │ const T = { │
304
+ │ Type.String(), │ │ anyOf: [{ │
305
+ │ Type.Number() │ │ type: 'string' │
306
+ │ ]) │ │ }, { │
307
+ │ │ │ type: 'number' │
308
+ │ │ │ }] │
309
+ │ │ │ } │
310
+ │ │ │ │
311
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
312
+ │ const T = Type.Intersect([ │ type T = { │ const T = { │
313
+ │ Type.Object({ │ x: number │ type: 'object', │
314
+ │ x: Type.Number() │ } & { │ properties: { │
315
+ │ }), │ y: number │ x: { │
316
+ │ Type.Object({ │ } │ type: 'number' │
317
+ │ y: Type.Number() │ │ }, │
318
+ │ }) │ │ y: { │
319
+ │ ]) │ │ type: 'number' │
320
+ │ │ │ } │
321
+ │ │ │ }, │
322
+ │ │ │ required: ['x', 'y'] │
323
+ │ │ │ } │
324
+ │ │ │ │
325
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
326
+ │ const T = Type.Never() │ type T = never │ const T = { │
327
+ │ │ │ allOf: [{ │
328
+ │ │ │ type: 'boolean', │
329
+ │ │ │ const: false │
330
+ │ │ │ }, { │
331
+ │ │ │ type: 'boolean', │
332
+ │ │ │ const: true │
333
+ │ │ │ }] │
334
+ │ │ │ } │
335
+ │ │ │ │
336
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
337
+ │ const T = Type.Record( │ type T = Record< │ const T = { │
338
+ │ Type.String(), │ string, │ type: 'object', │
339
+ │ Type.Number() │ number, │ patternProperties: { │
340
+ │ ) │ > │ '^.*$': { │
341
+ │ │ │ type: 'number' │
342
+ │ │ │ } │
343
+ │ │ │ } │
344
+ │ │ │ } │
345
+ │ │ │ │
346
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
347
+ │ const T = Type.Partial( │ type T = Partial<{ │ const T = { │
348
+ │ Type.Object({ │ x: number, │ type: 'object', │
349
+ │ x: Type.Number(), │ y: number │ properties: { │
350
+ │ y: Type.Number() | }> │ x: { │
351
+ │ }) │ │ type: 'number' │
352
+ │ ) │ │ }, │
353
+ │ │ │ y: { │
354
+ │ │ │ type: 'number' │
355
+ │ │ │ } │
356
+ │ │ │ } │
357
+ │ │ │ } │
358
+ │ │ │ │
359
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
360
+ │ const T = Type.Required( │ type T = Required<{ │ const T = { │
361
+ │ Type.Object({ │ x?: number, │ type: 'object', │
362
+ │ x: Type.Optional( │ y?: number │ properties: { │
363
+ │ Type.Number() | }> │ x: { │
364
+ │ ), │ │ type: 'number' │
365
+ │ y: Type.Optional( │ │ }, │
366
+ │ Type.Number() │ │ y: { │
367
+ │ ) │ │ type: 'number' │
368
+ │ }) │ │ } │
369
+ │ ) │ │ }, │
370
+ │ │ │ required: ['x', 'y'] │
371
+ │ │ │ } │
372
+ │ │ │ │
373
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
374
+ │ const T = Type.Pick( │ type T = Pick<{ │ const T = { │
375
+ │ Type.Object({ │ x: number, │ type: 'object', │
376
+ │ x: Type.Number(), │ y: number │ properties: { │
377
+ │ y: Type.Number() | }, 'x'> │ x: { │
378
+ │ }), ['x'] │ │ type: 'number' │
379
+ │ ) │ │ } │
380
+ │ │ │ }, │
381
+ │ │ │ required: ['x'] │
382
+ │ │ │ } │
383
+ │ │ │ │
384
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
385
+ │ const T = Type.Omit( │ type T = Omit<{ │ const T = { │
386
+ │ Type.Object({ │ x: number, │ type: 'object', │
387
+ │ x: Type.Number(), │ y: number │ properties: { │
388
+ │ y: Type.Number() | }, 'x'> │ y: { │
389
+ │ }), ['x'] │ │ type: 'number' │
390
+ │ ) │ │ } │
391
+ │ │ │ }, │
392
+ │ │ │ required: ['y'] │
393
+ │ │ │ } │
394
+ │ │ │ │
395
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
396
+ ```
397
+
398
+ <a name='types-extended'></a>
399
+
400
+ ### Extended
401
+
402
+ TypeBox provides a set of extended types that can be used to express schematics for core JavaScript constructs and primitives. Extended types are not valid JSON Schema and will not validate using typical validation. These types however can be used to frame JSON schema and describe callable RPC interfaces that may receive JSON validated data.
403
+
404
+ ```typescript
405
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
406
+ │ TypeBox │ TypeScript │ Extended Schema │
407
+ │ │ │ │
408
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
409
+ │ const T = Type.Constructor([ │ type T = new ( │ const T = { │
410
+ │ Type.String(), │ arg0: string, │ type: 'object', │
411
+ │ Type.Number() │ arg1: number │ instanceOf: 'Constructor', │
412
+ │ ], Type.Boolean()) │ ) => boolean │ parameters: [{ │
413
+ │ │ │ type: 'string' │
414
+ │ │ │ }, { │
415
+ │ │ │ type: 'number' │
416
+ │ │ │ }], │
417
+ │ │ │ return: { │
418
+ │ │ │ type: 'boolean' │
419
+ │ │ │ } │
420
+ │ │ │ } │
421
+ │ │ │ │
422
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
423
+ │ const T = Type.Function([ │ type T = ( │ const T = { │
424
+ | Type.String(), │ arg0: string, │ type : 'object', │
425
+ │ Type.Number() │ arg1: number │ instanceOf: 'Function', │
426
+ │ ], Type.Boolean()) │ ) => boolean │ parameters: [{ │
427
+ │ │ │ type: 'string' │
428
+ │ │ │ }, { │
429
+ │ │ │ type: 'number' │
430
+ │ │ │ }], │
431
+ │ │ │ return: { │
432
+ │ │ │ type: 'boolean' │
433
+ │ │ │ } │
434
+ │ │ │ } │
435
+ │ │ │ │
436
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
437
+ │ const T = Type.Promise( │ type T = Promise<string> │ const T = { │
438
+ │ Type.String() │ │ type: 'object', │
439
+ │ ) │ │ instanceOf: 'Promise', │
440
+ │ │ │ item: { │
441
+ │ │ │ type: 'string' │
442
+ │ │ │ } │
443
+ │ │ │ } │
444
+ │ │ │ │
445
+ │ │ │ │
446
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
447
+ │ const T = Type.Uint8Array() │ type T = Uint8Array │ const T = { │
448
+ │ │ │ type: 'object', │
449
+ │ │ │ instanceOf: 'Uint8Array' │
450
+ │ │ │ } │
451
+ │ │ │ │
452
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
453
+ │ const T = Type.Date() │ type T = Date │ const T = { │
454
+ │ │ │ type: 'object', │
455
+ │ │ │ instanceOf: 'Date' │
456
+ │ │ │ } │
457
+ │ │ │ │
458
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
459
+ │ const T = Type.Undefined() │ type T = undefined │ const T = { │
460
+ │ │ │ type: 'null', │
461
+ │ │ │ typeOf: 'Undefined' │
462
+ │ │ │ } │
463
+ │ │ │ │
464
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
465
+ │ const T = Type.Void() │ type T = void │ const T = { │
466
+ │ │ │ type: 'null' │
467
+ │ │ │ typeOf: 'Void' │
468
+ │ │ │ } │
469
+ │ │ │ │
470
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
471
+ ```
472
+
473
+ <a name='types-modifiers'></a>
474
+
475
+ ### Modifiers
476
+
477
+ 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.
478
+
479
+ ```typescript
480
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
481
+ │ TypeBox │ TypeScript │ JSON Schema │
482
+ │ │ │ │
483
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
484
+ │ const T = Type.Object({ │ type T = { │ const T = { │
485
+ │ name: Type.Optional( │ name?: string │ type: 'object', │
486
+ │ Type.String() │ } │ properties: { │
487
+ │ ) │ │ name: { │
488
+ │ }) │ │ type: 'string' │
489
+ │ │ │ } │
490
+ │ │ │ } │
491
+ │ │ │ } │
492
+ │ │ │ │
493
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
494
+ │ const T = Type.Object({ │ type T = { │ const T = { │
495
+ │ name: Type.Readonly( │ readonly name: string │ type: 'object', │
496
+ │ Type.String() │ } │ properties: { │
497
+ │ ) │ │ name: { │
498
+ │ }) │ │ type: 'string' │
499
+ │ │ │ } │
500
+ │ │ │ }, │
501
+ │ │ │ required: ['name'] │
502
+ │ │ │ } │
503
+ │ │ │ │
504
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
505
+ │ const T = Type.Object({ │ type T = { │ const T = { │
506
+ │ name: Type.ReadonlyOptional( │ readonly name?: string │ type: 'object', │
507
+ │ Type.String() │ } │ properties: { │
508
+ │ ) │ │ name: { │
509
+ │ }) │ │ type: 'string' │
510
+ │ │ │ } │
511
+ │ │ │ } │
512
+ │ │ │ } │
513
+ │ │ │ │
514
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
515
+ ```
516
+
517
+ <a name='types-options'></a>
518
+
519
+ ### Options
520
+
521
+ You can pass additional JSON schema options on the last argument of any given type. The following are some examples.
522
+
523
+ ```typescript
524
+ // string must be an email
525
+ const T = Type.String({ format: 'email' })
526
+
527
+ // number must be a multiple of 2
528
+ const T = Type.Number({ multipleOf: 2 })
529
+
530
+ // array must have at least 5 integer values
531
+ const T = Type.Array(Type.Integer(), { minItems: 5 })
532
+ ```
533
+
534
+ <a name='types-reference'></a>
535
+
536
+ ### Reference
537
+
538
+ Use `Type.Ref(...)` to create referenced types. The target type must specify an `$id`.
539
+
540
+ ```typescript
541
+ const T = Type.String({ $id: 'T' }) // const T = {
542
+ // $id: 'T',
543
+ // type: 'string'
544
+ // }
545
+
546
+ const R = Type.Ref(T) // const R = {
547
+ // $ref: 'T'
548
+ // }
549
+ ```
550
+
551
+ <a name='types-recursive'></a>
552
+
553
+ ### Recursive
554
+
555
+ Use `Type.Recursive(...)` to create recursive types.
556
+
557
+ ```typescript
558
+ const Node = Type.Recursive(Node => Type.Object({ // const Node = {
559
+ id: Type.String(), // $id: 'Node',
560
+ nodes: Type.Array(Node) // type: 'object',
561
+ }), { $id: 'Node' }) // properties: {
562
+ // id: {
563
+ // type: 'string'
564
+ // },
565
+ // nodes: {
566
+ // type: 'array',
567
+ // items: {
568
+ // $ref: 'Node'
569
+ // }
570
+ // }
571
+ // },
572
+ // required: [
573
+ // 'id',
574
+ // 'nodes'
575
+ // ]
576
+ // }
577
+
578
+ type Node = Static<typeof Node> // type Node = {
579
+ // id: string
580
+ // nodes: Node[]
581
+ // }
582
+
583
+ function test(node: Node) {
584
+ const id = node.nodes[0].nodes[0] // id is string
585
+ .nodes[0].nodes[0]
586
+ .id
587
+ }
588
+ ```
589
+
590
+ <a name='types-generic'></a>
591
+
592
+ ### Generic
593
+
594
+ Use functions to create generic types. The following creates a generic `Nullable<T>` type.
595
+
596
+ ```typescript
597
+ import { Type, Static, TSchema } from '@sinclair/typebox'
598
+
599
+ const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()])
600
+
601
+ const T = Nullable(Type.String()) // const T = {
602
+ // anyOf: [{
603
+ // type: 'string'
604
+ // }, {
605
+ // type: 'null'
606
+ // }]
607
+ // }
608
+
609
+ type T = Static<typeof T> // type T = string | null
610
+
611
+ const U = Nullable(Type.Number()) // const U = {
612
+ // anyOf: [{
613
+ // type: 'number'
614
+ // }, {
615
+ // type: 'null'
616
+ // }]
617
+ // }
618
+
619
+ type U = Static<typeof U> // type U = number | null
620
+ ```
621
+
622
+ <a name='types-conditional'></a>
623
+
624
+ ### Conditional
625
+
626
+ 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.
627
+
628
+ The conditional module is provided as an optional import.
629
+
630
+ ```typescript
631
+ import { Conditional } from '@sinclair/typebox/conditional'
632
+ ```
633
+ The following table shows the TypeBox mappings between TypeScript and JSON schema.
634
+
635
+ ```typescript
636
+ ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
637
+ │ TypeBox │ TypeScript │ JSON Schema │
638
+ │ │ │ │
639
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
640
+ │ const T = Conditional.Extends( │ type T = │ const T = { │
641
+ │ Type.String(), │ string extends number │ const: false, │
642
+ │ Type.Number(), │ true : false │ type: 'boolean' │
643
+ │ Type.Literal(true), │ │ } │
644
+ │ Type.Literal(false) │ │ │
645
+ │ ) │ │ │
646
+ │ │ │ │
647
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
648
+ │ const T = Conditional.Extract( │ type T = Extract< │ const T = { │
649
+ │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
650
+ │ Type.Literal('a'), │ 'a' | 'f' │ const: 'a' │
651
+ │ Type.Literal('b'), │ > │ type: 'string' │
652
+ │ Type.Literal('c') │ │ }] │
653
+ │ ]), │ │ } │
654
+ │ Type.Union([ │ │ │
655
+ │ Type.Literal('a'), │ │ │
656
+ │ Type.Literal('f') │ │ │
657
+ │ ]) │ │ │
658
+ │ ) │ │ │
659
+ │ │ │ │
660
+ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
661
+ │ const T = Conditional.Exclude( │ type T = Exclude< │ const T = { │
662
+ │ Type.Union([ │ 'a' | 'b' | 'c', │ anyOf: [{ │
663
+ │ Type.Literal('a'), │ 'a' │ const: 'b', │
664
+ │ Type.Literal('b'), │ > │ type: 'string' │
665
+ │ Type.Literal('c') │ │ }, { │
666
+ │ ]), │ │ const: 'c', │
667
+ │ Type.Union([ │ │ type: 'string' │
668
+ │ Type.Literal('a') │ │ }] │
669
+ │ ]) │ │ } │
670
+ │ ) │ │ │
671
+ │ │ │ │
672
+ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
673
+ ```
674
+
675
+ <a name='types-unsafe'></a>
676
+
677
+ ### Unsafe
678
+
679
+ Use `Type.Unsafe(...)` to create custom schemas with user defined inference rules.
680
+
681
+ ```typescript
682
+ const T = Type.Unsafe<string>({ type: 'number' }) // const T = {
683
+ // type: 'number'
684
+ // }
685
+
686
+ type T = Static<typeof T> // type T = string
687
+ ```
688
+
689
+ 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.
690
+
691
+ ```typescript
692
+ import { Type, Static, TSchema } from '@sinclair/typebox'
693
+
694
+ //--------------------------------------------------------------------------------------------
695
+ //
696
+ // Nullable<T>
697
+ //
698
+ //--------------------------------------------------------------------------------------------
699
+
700
+ function Nullable<T extends TSchema>(schema: T) {
701
+ return Type.Unsafe<Static<T> | null>({ ...schema, nullable: true })
702
+ }
703
+
704
+ const T = Nullable(Type.String()) // const T = {
705
+ // type: 'string',
706
+ // nullable: true
707
+ // }
708
+
709
+ type T = Static<typeof T> // type T = string | null
710
+
711
+
712
+ //--------------------------------------------------------------------------------------------
713
+ //
714
+ // StringEnum<string[]>
715
+ //
716
+ //--------------------------------------------------------------------------------------------
717
+
718
+ function StringEnum<T extends string[]>(values: [...T]) {
719
+ return Type.Unsafe<T[number]>({ type: 'string', enum: values })
720
+ }
721
+
722
+ const T = StringEnum(['A', 'B', 'C']) // const T = {
723
+ // enum: ['A', 'B', 'C']
724
+ // }
725
+
726
+ type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
727
+ ```
728
+
729
+ <a name='types-guards'></a>
730
+
731
+ ### Guards
732
+
733
+ Use the guard module to test if values are TypeBox types.
734
+
735
+ ```typescript
736
+ import { TypeGuard } from '@sinclair/typebox/guard'
737
+
738
+ const T = Type.String()
739
+
740
+ if(TypeGuard.TString(T)) {
741
+
742
+ // T is TString
743
+ }
744
+ ```
745
+
746
+ <a name='types-strict'></a>
747
+
748
+ ### Strict
749
+
750
+ 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.
751
+
752
+ ```typescript
753
+ const T = Type.Object({ // const T = {
754
+ name: Type.Optional(Type.String()) // [Kind]: 'Object',
755
+ }) // type: 'object',
756
+ // properties: {
757
+ // name: {
758
+ // [Kind]: 'String',
759
+ // type: 'string',
760
+ // [Modifier]: 'Optional'
761
+ // }
762
+ // }
763
+ // }
764
+
765
+ const U = Type.Strict(T) // const U = {
766
+ // type: 'object',
767
+ // properties: {
768
+ // name: {
769
+ // type: 'string'
770
+ // }
771
+ // }
772
+ // }
773
+ ```
774
+
775
+ <a name='values'></a>
776
+
777
+ ## Values
778
+
779
+ 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.
780
+
781
+ ```typescript
782
+ import { Value } from '@sinclair/typebox/value'
783
+ ```
784
+
785
+ <a name='values-create'></a>
786
+
787
+ ### Create
788
+
789
+ Use the Create function to create a value from a TypeBox type. TypeBox will use default values if specified.
790
+
791
+ ```typescript
792
+ const T = Type.Object({ x: Type.Number(), y: Type.Number({ default: 42 }) })
793
+
794
+ const A = Value.Create(T) // const A = { x: 0, y: 42 }
795
+ ```
796
+
797
+ <a name='values-clone'></a>
798
+
799
+ ### Clone
800
+
801
+ Use the Clone function to deeply clone a value
802
+
803
+ ```typescript
804
+ const A = Value.Clone({ x: 1, y: 2, z: 3 }) // const A = { x: 1, y: 2, z: 3 }
805
+ ```
806
+
807
+ <a name='values-check'></a>
808
+
809
+ ### Check
810
+
811
+ Use the Check function to type check a value
812
+
813
+ ```typescript
814
+ const T = Type.Object({ x: Type.Number() })
815
+
816
+ const R = Value.Check(T, { x: 1 }) // const R = true
817
+ ```
818
+
819
+ <a name='values-cast'></a>
820
+
821
+ ### Cast
822
+
823
+ 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.
824
+
825
+ ```typescript
826
+ const T = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false })
827
+
828
+ const X = Value.Cast(T, null) // const X = { x: 0, y: 0 }
829
+
830
+ const Y = Value.Cast(T, { x: 1 }) // const Y = { x: 1, y: 0 }
831
+
832
+ const Z = Value.Cast(T, { x: 1, y: 2, z: 3 }) // const Z = { x: 1, y: 2 }
833
+ ```
834
+
835
+ <a name='values-equal'></a>
836
+
837
+ ### Equal
838
+
839
+ Use the Equal function to deeply check for value equality.
840
+
841
+ ```typescript
842
+ const R = Value.Equal( // const R = true
843
+ { x: 1, y: 2, z: 3 },
844
+ { x: 1, y: 2, z: 3 }
845
+ )
846
+ ```
847
+
848
+ <a name='values-hash'></a>
849
+
850
+ ### Hash
851
+
852
+ Use the Hash function to create a [FNV1A-64](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) non cryptographic hash of a value.
853
+
854
+ ```typescript
855
+ const A = Value.Hash({ x: 1, y: 2, z: 3 }) // const A = 2910466848807138541n
856
+
857
+ const B = Value.Hash({ x: 1, y: 4, z: 3 }) // const B = 1418369778807423581n
858
+ ```
859
+
860
+ <a name='values-diff'></a>
861
+
862
+ ### Diff
863
+
864
+ Use the Diff function to produce a sequence of edits to transform one value into another.
865
+
866
+ ```typescript
867
+ const E = Value.Diff( // const E = [
868
+ { x: 1, y: 2, z: 3 }, // { type: 'update', path: '/y', value: 4 },
869
+ { y: 4, z: 5, w: 6 } // { type: 'update', path: '/z', value: 5 },
870
+ ) // { type: 'insert', path: '/w', value: 6 },
871
+ // { type: 'delete', path: '/x' }
872
+ // ]
873
+ ```
874
+
875
+ <a name='values-patch'></a>
876
+
877
+ ### Patch
878
+
879
+ Use the Patch function to apply edits
880
+
881
+ ```typescript
882
+ const A = { x: 1, y: 2 }
883
+
884
+ const B = { x: 3 }
885
+
886
+ const E = Value.Diff(A, B) // const E = [
887
+ // { type: 'update', path: '/x', value: 3 },
888
+ // { type: 'delete', path: '/y' }
889
+ // ]
890
+
891
+ const C = Value.Patch<typeof B>(A, E) // const C = { x: 3 }
892
+ ```
893
+
894
+
895
+ <a name='values-errors'></a>
896
+
897
+ ### Errors
898
+
899
+ Use the Errors function enumerate validation errors.
900
+
901
+ ```typescript
902
+ const T = Type.Object({ x: Type.Number(), y: Type.Number() })
903
+
904
+ const R = [...Value.Errors(T, { x: '42' })] // const R = [{
905
+ // schema: { type: 'number' },
906
+ // path: '/x',
907
+ // value: '42',
908
+ // message: 'Expected number'
909
+ // }, {
910
+ // schema: { type: 'number' },
911
+ // path: '/y',
912
+ // value: undefined,
913
+ // message: 'Expected number'
914
+ // }]
915
+ ```
916
+
917
+ <a name='values-pointer'></a>
918
+
919
+ ### Pointer
920
+
921
+ Use ValuePointer to perform mutable updates on existing values using [RFC6901](https://www.rfc-editor.org/rfc/rfc6901) Json Pointers.
922
+
923
+ ```typescript
924
+ import { ValuePointer } from '@sinclair/typebox/value'
925
+
926
+ const A = { x: 0, y: 0, z: 0 }
927
+
928
+ ValuePointer.Set(A, '/x', 1) // const A = { x: 1, y: 0, z: 0 }
929
+ ValuePointer.Set(A, '/y', 1) // const A = { x: 1, y: 1, z: 0 }
930
+ ValuePointer.Set(A, '/z', 1) // const A = { x: 1, y: 1, z: 1 }
931
+ ```
932
+ <a name='typecheck'></a>
933
+
934
+ ## TypeCheck
935
+
936
+ TypeBox constructs JSON Schema draft 6 compliant schematics and can be used with any validator that supports this specification. In JavaScript, an ideal validator to use is Ajv which supports draft 6 as well as more recent revisions to the specification. In addition to Ajv, TypeBox provides an optional built in type compiler which can offer faster runtime type compilation, as well as providing high performance data validation for TypeBox types only.
937
+
938
+ The following sections detail using these validators.
939
+
940
+ <a name='typecheck-ajv'></a>
941
+
942
+ ## Ajv
943
+
944
+ The following shows the recommended setup for Ajv.
945
+
946
+ ```bash
947
+ $ npm install ajv ajv-formats --save
948
+ ```
949
+
950
+ ```typescript
951
+ import { Type } from '@sinclair/typebox'
952
+ import addFormats from 'ajv-formats'
953
+ import Ajv from 'ajv'
954
+
955
+ const ajv = addFormats(new Ajv({}), [
956
+ 'date-time',
957
+ 'time',
958
+ 'date',
959
+ 'email',
960
+ 'hostname',
961
+ 'ipv4',
962
+ 'ipv6',
963
+ 'uri',
964
+ 'uri-reference',
965
+ 'uuid',
966
+ 'uri-template',
967
+ 'json-pointer',
968
+ 'relative-json-pointer',
969
+ 'regex'
970
+ ])
971
+
972
+ const C = ajv.compile(Type.Object({
973
+ x: Type.Number(),
974
+ y: Type.Number(),
975
+ z: Type.Number()
976
+ }))
977
+
978
+ const R = C({ x: 1, y: 2, z: 3 }) // const R = true
979
+ ```
980
+
981
+ <a name='typecheck-typecompiler'></a>
982
+
983
+ ### TypeCompiler
984
+
985
+ The TypeCompiler is a Just-In-Time (JIT) runtime compiler that can be used to convert TypeBox types into fast validation routines. This compiler is specifically tuned for fast compilation and validation for TypeBox types only.
986
+
987
+ The TypeCompiler is provided as an optional import.
988
+
989
+ ```typescript
990
+ import { TypeCompiler } from '@sinclair/typebox/compiler'
991
+ ```
992
+
993
+ Use the `Compile(...)` function to compile a type.
994
+
995
+ ```typescript
996
+ const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
997
+ x: Type.Number(), // x: TNumber;
998
+ y: Type.Number(), // y: TNumber;
999
+ z: Type.Number() // z: TNumber;
1000
+ })) // }>>
1001
+
1002
+ const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true
1003
+ ```
1004
+
1005
+ Use `Errors(...)` to generate diagnostics for a value. The `Errors(...)` function will run an exhaustive check across the value and yield any error found. For performance, this function should only be called after failed `Check(...)`.
1006
+
1007
+ ```typescript
1008
+ const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
1009
+ x: Type.Number(), // x: TNumber;
1010
+ y: Type.Number(), // y: TNumber;
1011
+ z: Type.Number() // z: TNumber;
1012
+ })) // }>>
1013
+
1014
+ const value = { }
1015
+
1016
+ const errors = [...C.Errors(value)] // const errors = [{
1017
+ // schema: { type: 'number' },
1018
+ // path: '/x',
1019
+ // value: undefined,
1020
+ // message: 'Expected number'
1021
+ // }, {
1022
+ // schema: { type: 'number' },
1023
+ // path: '/y',
1024
+ // value: undefined,
1025
+ // message: 'Expected number'
1026
+ // }, {
1027
+ // schema: { type: 'number' },
1028
+ // path: '/z',
1029
+ // value: undefined,
1030
+ // message: 'Expected number'
1031
+ // }]
1032
+ ```
1033
+
1034
+ Compiled routines can be inspected with the `.Code()` function.
1035
+
1036
+ ```typescript
1037
+ const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString>
1038
+
1039
+ console.log(C.Code()) // return function check(value) {
1040
+ // return (
1041
+ // (typeof value === 'string')
1042
+ // )
1043
+ // }
1044
+ ```
1045
+
1046
+ <a name='typesystem'></a>
1047
+
1048
+ ## TypeSystem
1049
+
1050
+ TypeBox provides an extensible TypeSystem module that enables developers to define additional types above and beyond the built in type set. This module also allows developers to define custom string formats as well as override certain type checking behaviours.
1051
+
1052
+ The TypeSystem module is provided as an optional import.
1053
+
1054
+ ```typescript
1055
+ import { TypeSystem } from '@sinclair/typebox/system'
1056
+ ```
1057
+
1058
+ <a name='typesystem-types'></a>
1059
+
1060
+ ### Types
1061
+
1062
+ Use the `CreateType(...)` function to specify custom type. This function will return a type factory function that can be used to construct the type. The following creates and registers a BigNumber type which will statically infer as `bigint`.
1063
+
1064
+ ```typescript
1065
+ //--------------------------------------------------------------------------------------------
1066
+ //
1067
+ // Use TypeSystem.CreateType(...) to define and return a type factory function
1068
+ //
1069
+ //--------------------------------------------------------------------------------------------
1070
+
1071
+ type BigNumberOptions = { minimum?: bigint; maximum?: bigint }
1072
+
1073
+ const BigNumber = TypeSystem.CreateType<bigint, BigNumberOptions>(
1074
+ 'BigNumber',
1075
+ (options, value) => {
1076
+ if (typeof value !== 'bigint') return false
1077
+ if (options.maximum !== undefined && value > options.maximum) return false
1078
+ if (options.minimum !== undefined && value < options.minimum) return false
1079
+ return true
1080
+ }
1081
+ )
1082
+
1083
+ //--------------------------------------------------------------------------------------------
1084
+ //
1085
+ // Use the custom type like any other type
1086
+ //
1087
+ //--------------------------------------------------------------------------------------------
1088
+
1089
+ const T = BigNumber({ minimum: 10n, maximum: 20n }) // const T = {
1090
+ // minimum: 10n,
1091
+ // maximum: 20n,
1092
+ // [Symbol(TypeBox.Kind)]: 'BigNumber'
1093
+ // }
1094
+
1095
+ const C = TypeCompiler.Compile(T)
1096
+ const X = C.Check(15n) // const X = true
1097
+ const Y = C.Check(5n) // const Y = false
1098
+ const Z = C.Check(25n) // const Z = false
1099
+ ```
1100
+
1101
+ <a name='typesystem-formats'></a>
1102
+
1103
+ ### Formats
1104
+
1105
+ Use the `CreateFormat(...)` function to specify user defined string formats. The following creates a custom string format that checks for lowercase.
1106
+
1107
+ ```typescript
1108
+ //--------------------------------------------------------------------------------------------
1109
+ //
1110
+ // Use TypeSystem.CreateFormat(...) to define a custom string format
1111
+ //
1112
+ //--------------------------------------------------------------------------------------------
1113
+
1114
+ TypeSystem.CreateFormat('lowercase', value => value === value.toLowerCase())
1115
+
1116
+ //--------------------------------------------------------------------------------------------
1117
+ //
1118
+ // Use the format by creating string types with the 'format' option
1119
+ //
1120
+ //--------------------------------------------------------------------------------------------
1121
+
1122
+ const T = Type.String({ format: 'lowercase' })
1123
+
1124
+ const A = Value.Check(T, 'action') // const A = true
1125
+
1126
+ const B = Value.Check(T, 'ACTION') // const B = false
1127
+ ```
1128
+
1129
+ <a name='benchmark'></a>
1130
+
1131
+ ## Benchmark
1132
+
1133
+ This project maintains a set of benchmarks that measure Ajv, Value and TypeCompiler compilation and validation performance. These benchmarks can be run locally by cloning this repository and running `npm run benchmark`. The results below show for Ajv version 8.11.2.
1134
+
1135
+ For additional comparative benchmarks, please refer to [typescript-runtime-type-benchmarks](https://moltar.github.io/typescript-runtime-type-benchmarks/).
1136
+
1137
+ <a name='benchmark-compile'></a>
1138
+
1139
+ ### Compile
1140
+
1141
+ 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).
1142
+
1143
+ ```typescript
1144
+ ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┐
1145
+ │ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │
1146
+ ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┤
1147
+ │ Number │ 2000 │ ' 451 ms' │ ' 16 ms' │ ' 28.19 x' │
1148
+ │ String │ 2000 │ ' 338 ms' │ ' 14 ms' │ ' 24.14 x' │
1149
+ │ Boolean │ 2000 │ ' 297 ms' │ ' 13 ms' │ ' 22.85 x' │
1150
+ │ Null │ 2000 │ ' 265 ms' │ ' 8 ms' │ ' 33.13 x' │
1151
+ │ RegEx │ 2000 │ ' 492 ms' ' 18 ms' ' 27.33 x'
1152
+ │ ObjectA │ 2000 │ ' 2744 ms' │ ' 55 ms' │ ' 49.89 x' │
1153
+ │ ObjectB │ 2000 │ ' 3005 ms' │ ' 44 ms' │ ' 68.30 x' │
1154
+ │ Tuple │ 2000 │ ' 1283 ms' │ ' 26 ms' │ ' 49.35 x' │
1155
+ │ Union │ 2000 │ ' 1263 ms' │ ' 27 ms' │ ' 46.78 x' │
1156
+ │ Vector4 │ 2000 │ ' 1622 ms' ' 23 ms' ' 70.52 x'
1157
+ │ Matrix4 │ 2000 │ ' 888 ms' │ ' 12 ms' │ ' 74.00 x' │
1158
+ │ Literal_String │ 2000 │ ' 344 ms' │ ' 14 ms' │ ' 24.57 x' │
1159
+ │ Literal_Number │ 2000 │ ' 389 ms' │ ' 8 ms' │ ' 48.63 x' │
1160
+ │ Literal_Boolean │ 2000 │ ' 374 ms' ' 9 ms' ' 41.56 x' │
1161
+ │ Array_Number │ 2000 │ ' 710 ms' │ ' 12 ms' │ ' 59.17 x' │
1162
+ │ Array_String │ 2000 │ ' 739 ms' │ ' 9 ms' │ ' 82.11 x' │
1163
+ │ Array_Boolean │ 2000 │ ' 732 ms' │ ' 7 ms' │ ' 104.57 x' │
1164
+ │ Array_ObjectA │ 2000 │ ' 3733 ms' │ ' 42 ms' │ ' 88.88 x' │
1165
+ Array_ObjectB │ 2000 │ ' 3602 ms' ' 42 ms' ' 85.76 x' │
1166
+ │ Array_Tuple │ 2000 │ ' 2204 ms' ' 20 ms' ' 110.20 x'
1167
+ │ Array_Union │ 2000 │ ' 1533 ms' ' 24 ms' ' 63.88 x'
1168
+ Array_Vector4 │ 2000 │ ' 2263 ms' │ ' 21 ms' │ ' 107.76 x' │
1169
+ │ Array_Matrix4 │ 2000 │ ' 1576 ms' │ ' 14 ms' │ ' 112.57 x' │
1170
+ └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┘
1171
+ ```
1172
+
1173
+ <a name='benchmark-validate'></a>
1174
+
1175
+ ### Validate
1176
+
1177
+ 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).
1178
+
1179
+ ```typescript
1180
+ ┌──────────────────┬────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
1181
+ (index) Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │
1182
+ ├──────────────────┼────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
1183
+ │ Number │ 1000000 │ ' 30 ms' │ ' 7 ms' │ ' 6 ms' │ ' 1.17 x' │
1184
+ │ String │ 1000000 │ ' 23 ms' │ ' 21 ms' │ ' 11 ms' │ ' 1.91 x' │
1185
+ │ Boolean │ 1000000 │ ' 22 ms' ' 21 ms' │ ' 10 ms' │ ' 2.10 x' │
1186
+ │ Null │ 1000000 │ ' 27 ms' ' 20 ms' │ ' 10 ms' │ ' 2.00 x' │
1187
+ │ RegEx │ 1000000 │ ' 163 ms' ' 47 ms' │ ' 38 ms' │ ' 1.24 x' │
1188
+ │ ObjectA │ 1000000 │ ' 654 ms' │ ' 41 ms' │ ' 24 ms' │ ' 1.71 x' │
1189
+ │ ObjectB │ 1000000 │ ' 1173 ms' │ ' 59 ms' │ ' 41 ms' │ ' 1.44 x' │
1190
+ │ Tuple │ 1000000 │ ' 124 ms' │ ' 24 ms' │ ' 17 ms' │ ' 1.41 x' │
1191
+ │ Union │ 1000000 │ ' 332 ms' │ ' 26 ms' │ ' 16 ms' │ ' 1.63 x' │
1192
+ │ Recursive │ 1000000 │ ' 3129 ms' │ ' 412 ms' │ ' 102 ms' │ ' 4.04 x' │
1193
+ │ Vector4 │ 1000000 │ ' 147 ms' │ ' 26 ms' │ ' 13 ms' │ ' 2.00 x' │
1194
+ │ Matrix4 │ 1000000 │ ' 576 ms' ' 41 ms' ' 28 ms' ' 1.46 x'
1195
+ │ Literal_String │ 1000000 │ ' 51 ms' │ ' 21 ms' │ ' 10 ms' │ ' 2.10 x' │
1196
+ │ Literal_Number │ 1000000 │ ' 47 ms' │ ' 21 ms' │ ' 11 ms' │ ' 1.91 x' │
1197
+ │ Literal_Boolean │ 1000000 │ ' 47 ms' │ ' 21 ms' │ ' 10 ms' │ ' 2.10 x' │
1198
+ │ Array_Number │ 1000000 │ ' 490 ms' │ ' 33 ms' │ ' 18 ms' │ ' 1.83 x' │
1199
+ │ Array_String │ 1000000 │ ' 502 ms' ' 31 ms' ' 25 ms' │ ' 1.24 x' │
1200
+ │ Array_Boolean │ 1000000 │ ' 465 ms' │ ' 33 ms' │ ' 27 ms' │ ' 1.22 x' │
1201
+ │ Array_ObjectA │ 1000000 │ ' 15463 ms' │ ' 2470 ms' │ ' 2052 ms' │ ' 1.20 x' │
1202
+ │ Array_ObjectB │ 1000000 │ ' 18047 ms' │ ' 2497 ms' │ ' 2348 ms' │ ' 1.06 x' │
1203
+ │ Array_Tuple │ 1000000 │ ' 1958 ms' ' 99 ms' ' 77 ms' │ ' 1.29 x' │
1204
+ │ Array_Union │ 1000000 │ ' 5348 ms' │ ' 254 ms' │ ' 89 ms' │ ' 2.85 x' │
1205
+ │ Array_Recursive │ 1000000 │ ' 54643 ms' │ ' 8870 ms' │ ' 1158 ms' │ ' 7.66 x' │
1206
+ │ Array_Vector4 │ 1000000 │ ' 2724 ms' │ ' 105 ms' │ ' 48 ms' │ ' 2.19 x' │
1207
+ │ Array_Matrix4 │ 1000000 │ ' 13821 ms' ' 437 ms' ' 266 ms' ' 1.64 x'
1208
+ └──────────────────┴────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
1209
+ ```
1210
+
1211
+ <a name='benchmark-compression'></a>
1212
+
1213
+ ### Compression
1214
+
1215
+ The following table lists esbuild compiled and minified sizes for each TypeBox module.
1216
+
1217
+ ```typescript
1218
+ ┌──────────────────────┬────────────┬────────────┬─────────────┐
1219
+ │ (index) │ Compiled │ Minified │ Compression │
1220
+ ├──────────────────────┼────────────┼────────────┼─────────────┤
1221
+ │ typebox/compiler │ ' 65.4 kb' │ ' 32.2 kb' │ '2.03 x' │
1222
+ typebox/conditional │ ' 45.5 kb' ' 18.6 kb' │ '2.45 x' │
1223
+ │ typebox/custom │ ' 0.6 kb' │ ' 0.2 kb' │ '2.61 x' │
1224
+ typebox/format │ ' 0.6 kb' ' 0.2 kb' │ '2.66 x' │
1225
+ │ typebox/guard │ ' 23.8 kb' │ ' 11.4 kb' │ '2.08 x' │
1226
+ typebox/hash │ ' 4.2 kb' │ ' 1.8 kb' │ '2.30 x' │
1227
+ │ typebox/system │ ' 14.0 kb' │ ' 7.1 kb' │ '1.96 x' │
1228
+ typebox/value │ ' 90.0 kb' │ ' 41.8 kb' │ '2.15 x' │
1229
+ │ typebox │ ' 12.0 kb' │ ' 6.4 kb' │ '1.89 x' │
1230
+ └──────────────────────┴────────────┴────────────┴─────────────┘
1231
+ ```
1232
+
1233
+ <a name='contribute'></a>
1234
+
1235
+ ## Contribute
1236
+
1237
+ 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.