@sinclair/typebox 0.34.10 → 0.34.12

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.
@@ -13,10 +13,11 @@ const index_8 = require("../type/registry/index");
13
13
  const index_9 = require("../type/keyof/index");
14
14
  const extends_undefined_1 = require("../type/extends/extends-undefined");
15
15
  const index_10 = require("../type/never/index");
16
+ const index_11 = require("../type/ref/index");
16
17
  // ------------------------------------------------------------------
17
18
  // ValueGuard
18
19
  // ------------------------------------------------------------------
19
- const index_11 = require("../value/guard/index");
20
+ const index_12 = require("../value/guard/index");
20
21
  // ------------------------------------------------------------------
21
22
  // TypeGuard
22
23
  // ------------------------------------------------------------------
@@ -211,17 +212,17 @@ var TypeCompiler;
211
212
  function* FromArray(schema, references, value) {
212
213
  yield `Array.isArray(${value})`;
213
214
  const [parameter, accumulator] = [CreateParameter('value', 'any'), CreateParameter('acc', 'number')];
214
- if ((0, index_11.IsNumber)(schema.maxItems))
215
+ if ((0, index_12.IsNumber)(schema.maxItems))
215
216
  yield `${value}.length <= ${schema.maxItems}`;
216
- if ((0, index_11.IsNumber)(schema.minItems))
217
+ if ((0, index_12.IsNumber)(schema.minItems))
217
218
  yield `${value}.length >= ${schema.minItems}`;
218
219
  const elementExpression = CreateExpression(schema.items, references, 'value');
219
220
  yield `${value}.every((${parameter}) => ${elementExpression})`;
220
- if ((0, type_1.IsSchema)(schema.contains) || (0, index_11.IsNumber)(schema.minContains) || (0, index_11.IsNumber)(schema.maxContains)) {
221
+ if ((0, type_1.IsSchema)(schema.contains) || (0, index_12.IsNumber)(schema.minContains) || (0, index_12.IsNumber)(schema.maxContains)) {
221
222
  const containsSchema = (0, type_1.IsSchema)(schema.contains) ? schema.contains : (0, index_10.Never)();
222
223
  const checkExpression = CreateExpression(containsSchema, references, 'value');
223
- const checkMinContains = (0, index_11.IsNumber)(schema.minContains) ? [`(count >= ${schema.minContains})`] : [];
224
- const checkMaxContains = (0, index_11.IsNumber)(schema.maxContains) ? [`(count <= ${schema.maxContains})`] : [];
224
+ const checkMinContains = (0, index_12.IsNumber)(schema.minContains) ? [`(count >= ${schema.minContains})`] : [];
225
+ const checkMaxContains = (0, index_12.IsNumber)(schema.maxContains) ? [`(count <= ${schema.maxContains})`] : [];
225
226
  const checkCount = `const count = value.reduce((${accumulator}, ${parameter}) => ${checkExpression} ? acc + 1 : acc, 0)`;
226
227
  const check = [`(count > 0)`, ...checkMinContains, ...checkMaxContains].join(' && ');
227
228
  yield `((${parameter}) => { ${checkCount}; return ${check}})(${value})`;
@@ -237,15 +238,15 @@ var TypeCompiler;
237
238
  }
238
239
  function* FromBigInt(schema, references, value) {
239
240
  yield `(typeof ${value} === 'bigint')`;
240
- if ((0, index_11.IsBigInt)(schema.exclusiveMaximum))
241
+ if ((0, index_12.IsBigInt)(schema.exclusiveMaximum))
241
242
  yield `${value} < BigInt(${schema.exclusiveMaximum})`;
242
- if ((0, index_11.IsBigInt)(schema.exclusiveMinimum))
243
+ if ((0, index_12.IsBigInt)(schema.exclusiveMinimum))
243
244
  yield `${value} > BigInt(${schema.exclusiveMinimum})`;
244
- if ((0, index_11.IsBigInt)(schema.maximum))
245
+ if ((0, index_12.IsBigInt)(schema.maximum))
245
246
  yield `${value} <= BigInt(${schema.maximum})`;
246
- if ((0, index_11.IsBigInt)(schema.minimum))
247
+ if ((0, index_12.IsBigInt)(schema.minimum))
247
248
  yield `${value} >= BigInt(${schema.minimum})`;
248
- if ((0, index_11.IsBigInt)(schema.multipleOf))
249
+ if ((0, index_12.IsBigInt)(schema.multipleOf))
249
250
  yield `(${value} % BigInt(${schema.multipleOf})) === 0`;
250
251
  }
251
252
  function* FromBoolean(schema, references, value) {
@@ -256,36 +257,37 @@ var TypeCompiler;
256
257
  }
257
258
  function* FromDate(schema, references, value) {
258
259
  yield `(${value} instanceof Date) && Number.isFinite(${value}.getTime())`;
259
- if ((0, index_11.IsNumber)(schema.exclusiveMaximumTimestamp))
260
+ if ((0, index_12.IsNumber)(schema.exclusiveMaximumTimestamp))
260
261
  yield `${value}.getTime() < ${schema.exclusiveMaximumTimestamp}`;
261
- if ((0, index_11.IsNumber)(schema.exclusiveMinimumTimestamp))
262
+ if ((0, index_12.IsNumber)(schema.exclusiveMinimumTimestamp))
262
263
  yield `${value}.getTime() > ${schema.exclusiveMinimumTimestamp}`;
263
- if ((0, index_11.IsNumber)(schema.maximumTimestamp))
264
+ if ((0, index_12.IsNumber)(schema.maximumTimestamp))
264
265
  yield `${value}.getTime() <= ${schema.maximumTimestamp}`;
265
- if ((0, index_11.IsNumber)(schema.minimumTimestamp))
266
+ if ((0, index_12.IsNumber)(schema.minimumTimestamp))
266
267
  yield `${value}.getTime() >= ${schema.minimumTimestamp}`;
267
- if ((0, index_11.IsNumber)(schema.multipleOfTimestamp))
268
+ if ((0, index_12.IsNumber)(schema.multipleOfTimestamp))
268
269
  yield `(${value}.getTime() % ${schema.multipleOfTimestamp}) === 0`;
269
270
  }
270
271
  function* FromFunction(schema, references, value) {
271
272
  yield `(typeof ${value} === 'function')`;
272
273
  }
273
274
  function* FromImport(schema, references, value) {
274
- const definitions = globalThis.Object.values(schema.$defs);
275
- const target = schema.$defs[schema.$ref];
276
- yield* Visit(target, [...references, ...definitions], value);
275
+ const members = globalThis.Object.getOwnPropertyNames(schema.$defs).reduce((result, key) => {
276
+ return [...result, schema.$defs[key]];
277
+ }, []);
278
+ yield* Visit((0, index_11.Ref)(schema.$ref), [...references, ...members], value);
277
279
  }
278
280
  function* FromInteger(schema, references, value) {
279
281
  yield `Number.isInteger(${value})`;
280
- if ((0, index_11.IsNumber)(schema.exclusiveMaximum))
282
+ if ((0, index_12.IsNumber)(schema.exclusiveMaximum))
281
283
  yield `${value} < ${schema.exclusiveMaximum}`;
282
- if ((0, index_11.IsNumber)(schema.exclusiveMinimum))
284
+ if ((0, index_12.IsNumber)(schema.exclusiveMinimum))
283
285
  yield `${value} > ${schema.exclusiveMinimum}`;
284
- if ((0, index_11.IsNumber)(schema.maximum))
286
+ if ((0, index_12.IsNumber)(schema.maximum))
285
287
  yield `${value} <= ${schema.maximum}`;
286
- if ((0, index_11.IsNumber)(schema.minimum))
288
+ if ((0, index_12.IsNumber)(schema.minimum))
287
289
  yield `${value} >= ${schema.minimum}`;
288
- if ((0, index_11.IsNumber)(schema.multipleOf))
290
+ if ((0, index_12.IsNumber)(schema.multipleOf))
289
291
  yield `(${value} % ${schema.multipleOf}) === 0`;
290
292
  }
291
293
  function* FromIntersect(schema, references, value) {
@@ -327,22 +329,22 @@ var TypeCompiler;
327
329
  }
328
330
  function* FromNumber(schema, references, value) {
329
331
  yield Policy.IsNumberLike(value);
330
- if ((0, index_11.IsNumber)(schema.exclusiveMaximum))
332
+ if ((0, index_12.IsNumber)(schema.exclusiveMaximum))
331
333
  yield `${value} < ${schema.exclusiveMaximum}`;
332
- if ((0, index_11.IsNumber)(schema.exclusiveMinimum))
334
+ if ((0, index_12.IsNumber)(schema.exclusiveMinimum))
333
335
  yield `${value} > ${schema.exclusiveMinimum}`;
334
- if ((0, index_11.IsNumber)(schema.maximum))
336
+ if ((0, index_12.IsNumber)(schema.maximum))
335
337
  yield `${value} <= ${schema.maximum}`;
336
- if ((0, index_11.IsNumber)(schema.minimum))
338
+ if ((0, index_12.IsNumber)(schema.minimum))
337
339
  yield `${value} >= ${schema.minimum}`;
338
- if ((0, index_11.IsNumber)(schema.multipleOf))
340
+ if ((0, index_12.IsNumber)(schema.multipleOf))
339
341
  yield `(${value} % ${schema.multipleOf}) === 0`;
340
342
  }
341
343
  function* FromObject(schema, references, value) {
342
344
  yield Policy.IsObjectLike(value);
343
- if ((0, index_11.IsNumber)(schema.minProperties))
345
+ if ((0, index_12.IsNumber)(schema.minProperties))
344
346
  yield `Object.getOwnPropertyNames(${value}).length >= ${schema.minProperties}`;
345
- if ((0, index_11.IsNumber)(schema.maxProperties))
347
+ if ((0, index_12.IsNumber)(schema.maxProperties))
346
348
  yield `Object.getOwnPropertyNames(${value}).length <= ${schema.maxProperties}`;
347
349
  const knownKeys = Object.getOwnPropertyNames(schema.properties);
348
350
  for (const knownKey of knownKeys) {
@@ -378,9 +380,9 @@ var TypeCompiler;
378
380
  }
379
381
  function* FromRecord(schema, references, value) {
380
382
  yield Policy.IsRecordLike(value);
381
- if ((0, index_11.IsNumber)(schema.minProperties))
383
+ if ((0, index_12.IsNumber)(schema.minProperties))
382
384
  yield `Object.getOwnPropertyNames(${value}).length >= ${schema.minProperties}`;
383
- if ((0, index_11.IsNumber)(schema.maxProperties))
385
+ if ((0, index_12.IsNumber)(schema.maxProperties))
384
386
  yield `Object.getOwnPropertyNames(${value}).length <= ${schema.maxProperties}`;
385
387
  const [patternKey, patternSchema] = Object.entries(schema.patternProperties)[0];
386
388
  const variable = CreateVariable(`${new RegExp(patternKey)}`);
@@ -392,29 +394,25 @@ var TypeCompiler;
392
394
  function* FromRef(schema, references, value) {
393
395
  const target = (0, index_5.Deref)(schema, references);
394
396
  // Reference: If we have seen this reference before we can just yield and return the function call.
395
- // If this isn't the case we defer to visit to generate and set the _recursion_end_for_ for subsequent
396
- // passes. This operation is very awkward as we are using the functions state to store values to
397
- // enable self referential types to terminate. This needs to be refactored.
398
- const recursiveEnd = `_recursion_end_for_${schema.$ref}`;
399
- if (state.functions.has(recursiveEnd))
397
+ // If this isn't the case we defer to visit to generate and set the function for subsequent passes.
398
+ if (state.functions.has(schema.$ref))
400
399
  return yield `${CreateFunctionName(schema.$ref)}(${value})`;
401
- state.functions.set(recursiveEnd, ''); // terminate recursion here by setting the name.
402
400
  yield* Visit(target, references, value);
403
401
  }
404
402
  function* FromRegExp(schema, references, value) {
405
403
  const variable = CreateVariable(`${new RegExp(schema.source, schema.flags)};`);
406
404
  yield `(typeof ${value} === 'string')`;
407
- if ((0, index_11.IsNumber)(schema.maxLength))
405
+ if ((0, index_12.IsNumber)(schema.maxLength))
408
406
  yield `${value}.length <= ${schema.maxLength}`;
409
- if ((0, index_11.IsNumber)(schema.minLength))
407
+ if ((0, index_12.IsNumber)(schema.minLength))
410
408
  yield `${value}.length >= ${schema.minLength}`;
411
409
  yield `${variable}.test(${value})`;
412
410
  }
413
411
  function* FromString(schema, references, value) {
414
412
  yield `(typeof ${value} === 'string')`;
415
- if ((0, index_11.IsNumber)(schema.maxLength))
413
+ if ((0, index_12.IsNumber)(schema.maxLength))
416
414
  yield `${value}.length <= ${schema.maxLength}`;
417
- if ((0, index_11.IsNumber)(schema.minLength))
415
+ if ((0, index_12.IsNumber)(schema.minLength))
418
416
  yield `${value}.length >= ${schema.minLength}`;
419
417
  if (schema.pattern !== undefined) {
420
418
  const variable = CreateVariable(`${new RegExp(schema.pattern)};`);
@@ -455,9 +453,9 @@ var TypeCompiler;
455
453
  }
456
454
  function* FromUint8Array(schema, references, value) {
457
455
  yield `${value} instanceof Uint8Array`;
458
- if ((0, index_11.IsNumber)(schema.maxByteLength))
456
+ if ((0, index_12.IsNumber)(schema.maxByteLength))
459
457
  yield `(${value}.length <= ${schema.maxByteLength})`;
460
- if ((0, index_11.IsNumber)(schema.minByteLength))
458
+ if ((0, index_12.IsNumber)(schema.minByteLength))
461
459
  yield `(${value}.length >= ${schema.minByteLength})`;
462
460
  }
463
461
  function* FromUnknown(schema, references, value) {
@@ -472,17 +470,21 @@ var TypeCompiler;
472
470
  yield `kind('${schema[index_7.Kind]}', ${instance}, ${value})`;
473
471
  }
474
472
  function* Visit(schema, references, value, useHoisting = true) {
475
- const references_ = (0, index_11.IsString)(schema.$id) ? [...references, schema] : references;
473
+ const references_ = (0, index_12.IsString)(schema.$id) ? [...references, schema] : references;
476
474
  const schema_ = schema;
477
475
  // --------------------------------------------------------------
478
476
  // Hoisting
479
477
  // --------------------------------------------------------------
480
- if (useHoisting && (0, index_11.IsString)(schema.$id)) {
478
+ if (useHoisting && (0, index_12.IsString)(schema.$id)) {
481
479
  const functionName = CreateFunctionName(schema.$id);
482
480
  if (state.functions.has(functionName)) {
483
481
  return yield `${functionName}(${value})`;
484
482
  }
485
483
  else {
484
+ // Note: In the case of cyclic types, we need to create a 'functions' record
485
+ // to prevent infinitely re-visiting the CreateFunction. Subsequent attempts
486
+ // to visit will be caught by the above condition.
487
+ state.functions.set(functionName, '<deferred>');
486
488
  const functionCode = CreateFunction(functionName, schema, references, 'value', false);
487
489
  state.functions.set(functionName, functionCode);
488
490
  return yield `${functionName}(${value})`;
@@ -607,7 +609,7 @@ var TypeCompiler;
607
609
  const functions = [...state.functions.values()];
608
610
  const variables = [...state.variables.values()];
609
611
  // prettier-ignore
610
- const checkFunction = (0, index_11.IsString)(schema.$id) // ensure top level schemas with $id's are hoisted
612
+ const checkFunction = (0, index_12.IsString)(schema.$id) // ensure top level schemas with $id's are hoisted
611
613
  ? `return function check(${parameter})${returns} {\n return ${CreateFunctionName(schema.$id)}(value)\n}`
612
614
  : `return ${functionCode}`;
613
615
  return [...variables, ...functions, checkFunction].join('\n');
@@ -616,8 +618,8 @@ var TypeCompiler;
616
618
  function Code(...args) {
617
619
  const defaults = { language: 'javascript' };
618
620
  // prettier-ignore
619
- const [schema, references, options] = (args.length === 2 && (0, index_11.IsArray)(args[1]) ? [args[0], args[1], defaults] :
620
- args.length === 2 && !(0, index_11.IsArray)(args[1]) ? [args[0], [], args[1]] :
621
+ const [schema, references, options] = (args.length === 2 && (0, index_12.IsArray)(args[1]) ? [args[0], args[1], defaults] :
622
+ args.length === 2 && !(0, index_12.IsArray)(args[1]) ? [args[0], [], args[1]] :
621
623
  args.length === 3 ? [args[0], args[1], args[2]] :
622
624
  args.length === 1 ? [args[0], [], defaults] :
623
625
  [null, [], defaults]);
@@ -8,6 +8,12 @@ const index_2 = require("../pointer/index");
8
8
  const index_3 = require("../clone/index");
9
9
  const index_4 = require("../../type/error/index");
10
10
  // ------------------------------------------------------------------
11
+ // IsStandardObject
12
+ // ------------------------------------------------------------------
13
+ function IsStandardObject(value) {
14
+ return (0, index_1.IsObject)(value) && !(0, index_1.IsArray)(value);
15
+ }
16
+ // ------------------------------------------------------------------
11
17
  // Errors
12
18
  // ------------------------------------------------------------------
13
19
  class ValueMutateError extends index_4.TypeBoxError {
@@ -17,7 +23,7 @@ class ValueMutateError extends index_4.TypeBoxError {
17
23
  }
18
24
  exports.ValueMutateError = ValueMutateError;
19
25
  function ObjectType(root, path, current, next) {
20
- if (!(0, index_1.IsObject)(current)) {
26
+ if (!IsStandardObject(current)) {
21
27
  index_2.ValuePointer.Set(root, path, (0, index_3.Clone)(next));
22
28
  }
23
29
  else {
@@ -69,7 +75,7 @@ function Visit(root, path, current, next) {
69
75
  return ArrayType(root, path, current, next);
70
76
  if ((0, index_1.IsTypedArray)(next))
71
77
  return TypedArrayType(root, path, current, next);
72
- if ((0, index_1.IsObject)(next))
78
+ if (IsStandardObject(next))
73
79
  return ObjectType(root, path, current, next);
74
80
  if ((0, index_1.IsValueType)(next))
75
81
  return ValueType(root, path, current, next);
@@ -82,8 +88,8 @@ function IsNonMutableValue(value) {
82
88
  }
83
89
  function IsMismatchedValue(current, next) {
84
90
  // prettier-ignore
85
- return (((0, index_1.IsObject)(current) && (0, index_1.IsArray)(next)) ||
86
- ((0, index_1.IsArray)(current) && (0, index_1.IsObject)(next)));
91
+ return ((IsStandardObject(current) && (0, index_1.IsArray)(next)) ||
92
+ ((0, index_1.IsArray)(current) && IsStandardObject(next)));
87
93
  }
88
94
  // ------------------------------------------------------------------
89
95
  // Mutate
@@ -9,6 +9,7 @@ import { TypeRegistry, FormatRegistry } from '../type/registry/index.mjs';
9
9
  import { KeyOfPattern } from '../type/keyof/index.mjs';
10
10
  import { ExtendsUndefinedCheck } from '../type/extends/extends-undefined.mjs';
11
11
  import { Never } from '../type/never/index.mjs';
12
+ import { Ref } from '../type/ref/index.mjs';
12
13
  // ------------------------------------------------------------------
13
14
  // ValueGuard
14
15
  // ------------------------------------------------------------------
@@ -264,9 +265,10 @@ export var TypeCompiler;
264
265
  yield `(typeof ${value} === 'function')`;
265
266
  }
266
267
  function* FromImport(schema, references, value) {
267
- const definitions = globalThis.Object.values(schema.$defs);
268
- const target = schema.$defs[schema.$ref];
269
- yield* Visit(target, [...references, ...definitions], value);
268
+ const members = globalThis.Object.getOwnPropertyNames(schema.$defs).reduce((result, key) => {
269
+ return [...result, schema.$defs[key]];
270
+ }, []);
271
+ yield* Visit(Ref(schema.$ref), [...references, ...members], value);
270
272
  }
271
273
  function* FromInteger(schema, references, value) {
272
274
  yield `Number.isInteger(${value})`;
@@ -385,13 +387,9 @@ export var TypeCompiler;
385
387
  function* FromRef(schema, references, value) {
386
388
  const target = Deref(schema, references);
387
389
  // Reference: If we have seen this reference before we can just yield and return the function call.
388
- // If this isn't the case we defer to visit to generate and set the _recursion_end_for_ for subsequent
389
- // passes. This operation is very awkward as we are using the functions state to store values to
390
- // enable self referential types to terminate. This needs to be refactored.
391
- const recursiveEnd = `_recursion_end_for_${schema.$ref}`;
392
- if (state.functions.has(recursiveEnd))
390
+ // If this isn't the case we defer to visit to generate and set the function for subsequent passes.
391
+ if (state.functions.has(schema.$ref))
393
392
  return yield `${CreateFunctionName(schema.$ref)}(${value})`;
394
- state.functions.set(recursiveEnd, ''); // terminate recursion here by setting the name.
395
393
  yield* Visit(target, references, value);
396
394
  }
397
395
  function* FromRegExp(schema, references, value) {
@@ -476,6 +474,10 @@ export var TypeCompiler;
476
474
  return yield `${functionName}(${value})`;
477
475
  }
478
476
  else {
477
+ // Note: In the case of cyclic types, we need to create a 'functions' record
478
+ // to prevent infinitely re-visiting the CreateFunction. Subsequent attempts
479
+ // to visit will be caught by the above condition.
480
+ state.functions.set(functionName, '<deferred>');
479
481
  const functionCode = CreateFunction(functionName, schema, references, 'value', false);
480
482
  state.functions.set(functionName, functionCode);
481
483
  return yield `${functionName}(${value})`;
@@ -3,6 +3,12 @@ import { ValuePointer } from '../pointer/index.mjs';
3
3
  import { Clone } from '../clone/index.mjs';
4
4
  import { TypeBoxError } from '../../type/error/index.mjs';
5
5
  // ------------------------------------------------------------------
6
+ // IsStandardObject
7
+ // ------------------------------------------------------------------
8
+ function IsStandardObject(value) {
9
+ return IsObject(value) && !IsArray(value);
10
+ }
11
+ // ------------------------------------------------------------------
6
12
  // Errors
7
13
  // ------------------------------------------------------------------
8
14
  export class ValueMutateError extends TypeBoxError {
@@ -11,7 +17,7 @@ export class ValueMutateError extends TypeBoxError {
11
17
  }
12
18
  }
13
19
  function ObjectType(root, path, current, next) {
14
- if (!IsObject(current)) {
20
+ if (!IsStandardObject(current)) {
15
21
  ValuePointer.Set(root, path, Clone(next));
16
22
  }
17
23
  else {
@@ -63,7 +69,7 @@ function Visit(root, path, current, next) {
63
69
  return ArrayType(root, path, current, next);
64
70
  if (IsTypedArray(next))
65
71
  return TypedArrayType(root, path, current, next);
66
- if (IsObject(next))
72
+ if (IsStandardObject(next))
67
73
  return ObjectType(root, path, current, next);
68
74
  if (IsValueType(next))
69
75
  return ValueType(root, path, current, next);
@@ -76,8 +82,8 @@ function IsNonMutableValue(value) {
76
82
  }
77
83
  function IsMismatchedValue(current, next) {
78
84
  // prettier-ignore
79
- return ((IsObject(current) && IsArray(next)) ||
80
- (IsArray(current) && IsObject(next)));
85
+ return ((IsStandardObject(current) && IsArray(next)) ||
86
+ (IsArray(current) && IsStandardObject(next)));
81
87
  }
82
88
  // ------------------------------------------------------------------
83
89
  // Mutate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.34.10",
3
+ "version": "0.34.12",
4
4
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
package/readme.md CHANGED
@@ -68,6 +68,7 @@ License MIT
68
68
  - [Options](#types-options)
69
69
  - [Properties](#types-properties)
70
70
  - [Generics](#types-generics)
71
+ - [Recursive](#types-recursive)
71
72
  - [Modules](#types-modules)
72
73
  - [Template Literal](#types-template-literal)
73
74
  - [Indexed](#types-indexed)
@@ -759,21 +760,51 @@ const T = Nullable(Type.String()) // const T = {
759
760
  type T = Static<typeof T> // type T = string | null
760
761
  ```
761
762
 
762
- <a name='types-modules'></a>
763
+ <a name='types-recursive'></a>
763
764
 
764
- ### Module Types
765
+ ### Recursive Types
765
766
 
766
- TypeBox Modules are containers for related types. They provide a referential namespace, enabling types to reference one another via string identifiers. Modules support both singular and mutually recursive referencing within the context of a module, as well as referential computed types (such as Partial + Ref). All Module types must be imported before use. TypeBox represents an imported type with the `$defs` Json Schema keyword.
767
+ Use the Recursive function to create a singular recursive type.
767
768
 
768
- #### Usage
769
+ ```typescript
770
+ const Node = Type.Recursive(Self => Type.Object({ // const Node = {
771
+ id: Type.String(), // $id: 'Node',
772
+ nodes: Type.Array(Self) // type: 'object',
773
+ }), { $id: 'Node' }) // properties: {
774
+ // id: {
775
+ // type: 'string'
776
+ // },
777
+ // nodes: {
778
+ // type: 'array',
779
+ // items: {
780
+ // $ref: 'Node'
781
+ // }
782
+ // }
783
+ // },
784
+ // required: [
785
+ // 'id',
786
+ // 'nodes'
787
+ // ]
788
+ // }
769
789
 
770
- The following creates a Module with User and PartialUser types. Note that the PartialUser type is specified as a Partial + Ref to the User type. It is not possible to perform a Partial operation directly on a reference, so TypeBox will return a TComputed type that defers the Partial operation until all types are resolved. The TComputed type is evaluated when calling Import on the Module.
790
+ type Node = Static<typeof Node> // type Node = {
791
+ // id: string
792
+ // nodes: Node[]
793
+ // }
771
794
 
772
- ```typescript
773
- // Module with PartialUser and User types
795
+ function test(node: Node) {
796
+ const id = node.nodes[0].nodes[0].id // id is string
797
+ }
798
+ ```
774
799
 
775
- const Module = Type.Module({
800
+ <a name='types-modules'></a>
801
+
802
+ ### Module Types
776
803
 
804
+ Module types are containers for a set of referential types. Modules act as namespaces, enabling types to reference one another via string identifiers. Modules support both singular and mutually recursive references, as well as deferred dereferencing for computed types such as Partial. Types imported from a module are expressed using the Json Schema `$defs` keyword.
805
+
806
+ ```typescript
807
+ const Module = Type.Module({
777
808
  PartialUser: Type.Partial(Type.Ref('User')), // TComputed<'Partial', [TRef<'User'>]>
778
809
 
779
810
  User: Type.Object({ // TObject<{
@@ -781,11 +812,7 @@ const Module = Type.Module({
781
812
  name: Type.String(), // name: TString,
782
813
  email: Type.String() // email: TString
783
814
  }), // }>
784
-
785
815
  })
786
-
787
- // Types must be imported before use.
788
-
789
816
  const User = Module.Import('User') // const User: TImport<{...}, 'User'>
790
817
 
791
818
  type User = Static<typeof User> // type User = {
@@ -803,7 +830,6 @@ type PartialUser = Static<typeof PartialUser> // type PartialUser = {
803
830
  // }
804
831
  ```
805
832
 
806
-
807
833
  <a name='types-template-literal'></a>
808
834
 
809
835
  ### Template Literal Types