@sinclair/typebox 0.28.20 → 0.29.0

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.
@@ -284,9 +284,8 @@ var TypeCompiler;
284
284
  yield `false`;
285
285
  }
286
286
  function* Not(schema, references, value) {
287
- const left = CreateExpression(schema.allOf[0].not, references, value);
288
- const right = CreateExpression(schema.allOf[1], references, value);
289
- yield `!${left} && ${right}`;
287
+ const expression = CreateExpression(schema.not, references, value);
288
+ yield `(!${expression})`;
290
289
  }
291
290
  function* Null(schema, references, value) {
292
291
  yield `(${value} === null)`;
package/errors/errors.js CHANGED
@@ -313,10 +313,9 @@ var ValueErrors;
313
313
  yield { type: ValueErrorType.Never, schema, path, value, message: `Value cannot be validated` };
314
314
  }
315
315
  function* Not(schema, references, path, value) {
316
- if (Visit(schema.allOf[0].not, references, path, value).next().done === true) {
316
+ if (Visit(schema.not, references, path, value).next().done === true) {
317
317
  yield { type: ValueErrorType.Not, schema, path, value, message: `Value should not validate` };
318
318
  }
319
- yield* Visit(schema.allOf[1], references, path, value);
320
319
  }
321
320
  function* Null(schema, references, path, value) {
322
321
  if (!(value === null)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.28.20",
3
+ "version": "0.29.0",
4
4
  "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
@@ -42,6 +42,6 @@
42
42
  "chai": "^4.3.6",
43
43
  "mocha": "^9.2.2",
44
44
  "prettier": "^2.7.1",
45
- "typescript": "^5.1.3"
45
+ "typescript": "^5.1.6"
46
46
  }
47
47
  }
package/readme.md CHANGED
@@ -84,6 +84,7 @@ License MIT
84
84
  - [Conditional](#types-conditional)
85
85
  - [Template Literal](#types-template-literal)
86
86
  - [Indexed](#types-indexed)
87
+ - [Not](#types-not)
87
88
  - [Rest](#types-rest)
88
89
  - [Guards](#types-guards)
89
90
  - [Unsafe](#types-unsafe)
@@ -353,20 +354,11 @@ The following table lists the Standard TypeBox types. These types are fully comp
353
354
  │ │ │ } │
354
355
  │ │ │ │
355
356
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
356
- │ const T = Type.Not( | type T = string │ const T = { │
357
- | Type.Union([ │ │ allOf: [{
358
- Type.Literal('x'), │ │ not: {
359
- Type.Literal('y'), │ │ anyOf: [
360
- │ Type.Literal('z') │ │ { const: 'x' }, │
361
- │ ]), │ │ { const: 'y' }, │
362
- │ Type.String() │ │ { const: 'z' } │
363
- │ ) │ │ ] │
364
- │ │ │ } │
365
- │ │ │ }, { │
366
- │ │ │ type: 'string' │
367
- │ │ │ }] │
357
+ │ const T = Type.Not( | type T = unknown │ const T = { │
358
+ Type.String() │ │ not: {
359
+ ) │ │ type: 'string'
360
+ │ │ }
368
361
  │ │ │ } │
369
- │ │ │ │
370
362
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
371
363
  │ const T = Type.Extends( │ type T = │ const T = { │
372
364
  │ Type.String(), │ string extends number │ const: false, │
@@ -650,7 +642,7 @@ const T = Type.String({ // const T = {
650
642
  }) // format: 'email'
651
643
  // }
652
644
 
653
- // Mumber must be a multiple of 2
645
+ // Number must be a multiple of 2
654
646
  const T = Type.Number({ // const T = {
655
647
  multipleOf: 2 // type: 'number',
656
648
  }) // multipleOf: 2
@@ -892,6 +884,49 @@ const C = Type.Index(T, Type.KeyOf(T)) // const C = {
892
884
  // }
893
885
  ```
894
886
 
887
+ <a name='types-not'></a>
888
+
889
+ ### Not Types
890
+
891
+ Not types are supported with `Type.Not`. This type represents the JSON Schema `not` keyword and will statically infer as `unknown`. Note that negated (or not) types are not supported in TypeScript, but can still be partially expressed by interpreting `not` as the broad type `unknown`. When used with intersect types, the Not type can create refined assertion rules for types by leveraging TypeScript's ability to narrow from `unknown` to an intended type through intersection.
892
+
893
+ For example, consider a type which is `number` but not `1 | 2 | 3` and where the static type would still technically be a `number`. The following shows a pseudo TypeScript example using `not` followed by the TypeBox implementation.
894
+
895
+ ```typescript
896
+ // Pseudo TypeScript
897
+
898
+ type T = number & not (1 | 2 | 3) // allow all numbers except 1, 2, 3
899
+
900
+ // TypeBox
901
+
902
+ const T = Type.Intersect([ // const T = {
903
+ Type.Number(), // allOf: [
904
+ Type.Not(Type.Union([ // { type: "number" },
905
+ Type.Literal(1), // {
906
+ Type.Literal(2), // not: {
907
+ Type.Literal(3) // anyOf: [
908
+ ])) // { const: 1, type: "number" },
909
+ ]) // { const: 2, type: "number" },
910
+ // { const: 3, type: "number" }
911
+ // ]
912
+ // }
913
+ // }
914
+ // ]
915
+ // }
916
+
917
+ type T = Static<typeof T> // evaluates as:
918
+ //
919
+ // type T = (number & (not (1 | 2 | 3)))
920
+ // type T = (number & (unknown))
921
+ // type T = (number)
922
+ ```
923
+
924
+ The Not type can be used with constraints to define schematics for types that would otherwise be difficult to express.
925
+ ```typescript
926
+ const Even = Type.Number({ multipleOf: 2 })
927
+
928
+ const Odd = Type.Intersect([Type.Number(), Type.Not(Even)])
929
+ ```
895
930
  <a name='types-rest'></a>
896
931
 
897
932
  ### Rest Types
@@ -1420,29 +1455,25 @@ TypeSystem.AllowNaN = true
1420
1455
 
1421
1456
  ## Workbench
1422
1457
 
1423
- TypeBox offers a small web based code generation tool that can be used to convert TypeScript types into TypeBox type definitions as well as a variety of other formats.
1458
+ TypeBox offers a web based code generation tool that can be used to convert TypeScript types into TypeBox types as well as a variety of other runtime type representations.
1424
1459
 
1425
1460
  [Workbench Link Here](https://sinclairzx81.github.io/typebox-workbench/)
1426
1461
 
1427
- <div align='center'>
1428
-
1429
- <a href="https://sinclairzx81.github.io/typebox-workbench/"><img src="https://github.com/sinclairzx81/typebox/blob/master/workbench.png?raw=true" /></a>
1430
-
1431
- </div>
1432
-
1433
1462
  <a name='ecosystem'></a>
1434
1463
 
1435
1464
  ## Ecosystem
1436
1465
 
1437
- The following is a list of community packages that provide general tooling and framework support for TypeBox.
1466
+ The following is a list of community packages that provide general tooling and framework integration support for TypeBox.
1438
1467
 
1439
1468
  | Package | Description |
1440
1469
  | ------------- | ------------- |
1441
1470
  | [elysia](https://github.com/elysiajs/elysia) | Fast and friendly Bun web framework |
1442
1471
  | [fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox) | Fastify TypeBox integration with the Fastify Type Provider |
1472
+ | [feathersjs](https://github.com/feathersjs/feathers) | The API and real-time application framework |
1443
1473
  | [fetch-typebox](https://github.com/erfanium/fetch-typebox) | Drop-in replacement for fetch that brings easy integration with TypeBox |
1444
1474
  | [schema2typebox](https://github.com/xddq/schema2typebox) | Creating TypeBox code from JSON schemas |
1445
- | [ts2typebox](https://github.com/xddq/ts2typebox) | Creating TypeBox code from Typescript types |
1475
+ | [ts2typebox](https://github.com/xddq/ts2typebox) | Creating TypeBox code from Typescript types |
1476
+ | [typebox-validators](https://github.com/jtlapp/typebox-validators) | Advanced validators supporting discriminated and heterogeneous unions |
1446
1477
 
1447
1478
  <a name='benchmark'></a>
1448
1479
 
package/typebox.d.ts CHANGED
@@ -169,14 +169,7 @@ export type TIndexType<T extends TSchema, K extends Key> = T extends TRecursive<
169
169
  ];
170
170
  export type TIndexRestMany<T extends TSchema, K extends Key[]> = K extends [infer L, ...infer R] ? [TIndexType<T, Assert<L, Key>>, ...TIndexRestMany<T, Assert<R, Key[]>>] : [
171
171
  ];
172
- export type TIndexReduce<T extends TSchema, K extends Key[]> = T extends TRecursive<infer S> ? TIndexReduce<S, K> : T extends TIntersect ? UnionType<Flat<TIndexRestMany<T, K>>> : T extends TUnion ? UnionType<Flat<TIndexRestMany<T, K>>> : T extends TObject ? UnionType<Flat<TIndexRestMany<T, K>>> : T extends TTuple ? UnionType<Flat<TIndexRestMany<T, K>>> : TNever;
173
- export type TIndex<T extends TSchema, K extends TSchema> = [
174
- T,
175
- K
176
- ] extends [TTuple, TNumber] ? UnionType<Assert<T['items'], TSchema[]>> : [
177
- T,
178
- K
179
- ] extends [TArray, TNumber] ? AssertType<T['items']> : K extends TTemplateLiteral ? TIndexReduce<T, TTemplateLiteralKeyRest<K>> : K extends TUnion<TLiteral<Key>[]> ? TIndexReduce<T, TUnionLiteralKeyRest<K>> : K extends TLiteral<Key> ? TIndexReduce<T, [K['const']]> : TNever;
172
+ export type TIndex<T extends TSchema, K extends Key[]> = T extends TRecursive<infer S> ? TIndex<S, K> : T extends TIntersect ? UnionType<Flat<TIndexRestMany<T, K>>> : T extends TUnion ? UnionType<Flat<TIndexRestMany<T, K>>> : T extends TObject ? UnionType<Flat<TIndexRestMany<T, K>>> : T extends TTuple ? UnionType<Flat<TIndexRestMany<T, K>>> : TNever;
180
173
  export interface TInteger extends TSchema, NumericOptions<number> {
181
174
  [Kind]: 'Integer';
182
175
  static: number;
@@ -214,12 +207,10 @@ export interface TNever extends TSchema {
214
207
  static: never;
215
208
  not: {};
216
209
  }
217
- export interface TNot<Not extends TSchema = TSchema, T extends TSchema = TSchema> extends TSchema {
210
+ export interface TNot<T extends TSchema = TSchema> extends TSchema {
218
211
  [Kind]: 'Not';
219
- static: Static<T>;
220
- allOf: [{
221
- not: Not;
222
- }, T];
212
+ static: T extends TNot<infer U> ? Static<U> : unknown;
213
+ not: T;
223
214
  }
224
215
  export interface TNull extends TSchema {
225
216
  [Kind]: 'Null';
@@ -662,9 +653,19 @@ export declare class StandardTypeBuilder extends TypeBuilder {
662
653
  /** `[Standard]` Extracts from the left type any type that is assignable to the right */
663
654
  Extract<L extends TSchema, R extends TSchema>(left: L, right: R, options?: SchemaOptions): TExtract<L, R>;
664
655
  /** `[Standard]` Returns indexed property types for the given keys */
665
- Index<T extends TSchema, K extends (keyof Static<T>)[]>(schema: T, keys: [...K], options?: SchemaOptions): TIndexReduce<T, Assert<K, Key[]>>;
656
+ Index<T extends TTuple, K extends TNumber>(schema: T, keys: K, options?: SchemaOptions): UnionType<Assert<T['items'], TSchema[]>>;
666
657
  /** `[Standard]` Returns indexed property types for the given keys */
667
- Index<T extends TSchema, K extends TSchema>(schema: T, key: K, options?: SchemaOptions): TIndex<T, K>;
658
+ Index<T extends TArray, K extends TNumber>(schema: T, keys: K, options?: SchemaOptions): AssertType<T['items']>;
659
+ /** `[Standard]` Returns indexed property types for the given keys */
660
+ Index<T extends TSchema, K extends TTemplateLiteral>(schema: T, keys: K, options?: SchemaOptions): TIndex<T, TTemplateLiteralKeyRest<K>>;
661
+ /** `[Standard]` Returns indexed property types for the given keys */
662
+ Index<T extends TSchema, K extends TLiteral<Key>>(schema: T, keys: K, options?: SchemaOptions): TIndex<T, [K['const']]>;
663
+ /** `[Standard]` Returns indexed property types for the given keys */
664
+ Index<T extends TSchema, K extends (keyof Static<T>)[]>(schema: T, keys: [...K], options?: SchemaOptions): TIndex<T, Assert<K, Key[]>>;
665
+ /** `[Standard]` Returns indexed property types for the given keys */
666
+ Index<T extends TSchema, K extends TUnion<TLiteral<Key>[]>>(schema: T, keys: K, options?: SchemaOptions): TIndex<T, TUnionLiteralKeyRest<K>>;
667
+ /** `[Standard]` Returns indexed property types for the given keys */
668
+ Index<T extends TSchema, K extends TSchema>(schema: T, key: K, options?: SchemaOptions): TSchema;
668
669
  /** `[Standard]` Creates an Integer type */
669
670
  Integer(options?: NumericOptions<number>): TInteger;
670
671
  /** `[Standard]` Creates a Intersect type */
@@ -678,8 +679,8 @@ export declare class StandardTypeBuilder extends TypeBuilder {
678
679
  Literal<T extends TLiteralValue>(value: T, options?: SchemaOptions): TLiteral<T>;
679
680
  /** `[Standard]` Creates a Never type */
680
681
  Never(options?: SchemaOptions): TNever;
681
- /** `[Standard]` Creates a Not type. The first argument is the disallowed type, the second is the allowed. */
682
- Not<N extends TSchema, T extends TSchema>(not: N, schema: T, options?: SchemaOptions): TNot<N, T>;
682
+ /** `[Standard]` Creates a Not type */
683
+ Not<T extends TSchema>(not: T, options?: SchemaOptions): TNot<T>;
683
684
  /** `[Standard]` Creates a Null type */
684
685
  Null(options?: SchemaOptions): TNull;
685
686
  /** `[Standard]` Creates a Number type */
package/typebox.js CHANGED
@@ -339,11 +339,7 @@ var TypeGuard;
339
339
  // prettier-ignore
340
340
  return (TKind(schema) &&
341
341
  schema[exports.Kind] === 'Not' &&
342
- IsArray(schema.allOf) &&
343
- schema.allOf.length === 2 &&
344
- IsObject(schema.allOf[0]) &&
345
- TSchema(schema.allOf[0].not) &&
346
- TSchema(schema.allOf[1]));
342
+ TSchema(schema.not));
347
343
  }
348
344
  TypeGuard.TNot = TNot;
349
345
  /** Returns true if the given schema is TNull */
@@ -622,8 +618,7 @@ var ExtendsUndefined;
622
618
  if (schema[exports.Kind] === 'Undefined')
623
619
  return true;
624
620
  if (schema[exports.Kind] === 'Not') {
625
- const not = schema;
626
- return Check(not.allOf[1]);
621
+ return !Check(schema.not);
627
622
  }
628
623
  if (schema[exports.Kind] === 'Intersect') {
629
624
  const intersect = schema;
@@ -890,6 +885,19 @@ var TypeExtends;
890
885
  return TypeExtendsResult.True;
891
886
  }
892
887
  // --------------------------------------------------------------------------
888
+ // Not
889
+ // --------------------------------------------------------------------------
890
+ function ResolveNot(schema) {
891
+ let [current, depth] = [schema, 0];
892
+ while (true) {
893
+ if (!TypeGuard.TNot(current))
894
+ break;
895
+ current = current.not;
896
+ depth += 1;
897
+ }
898
+ return depth % 2 === 0 ? current : exports.Type.Unknown();
899
+ }
900
+ // --------------------------------------------------------------------------
893
901
  // Null
894
902
  // --------------------------------------------------------------------------
895
903
  function Null(left, right) {
@@ -1309,6 +1317,11 @@ var TypeExtends;
1309
1317
  return TypeGuard.TVoid(right) ? TypeExtendsResult.True : TypeExtendsResult.False;
1310
1318
  }
1311
1319
  function Visit(left, right) {
1320
+ // Not Unwrap
1321
+ if (TypeGuard.TNot(left))
1322
+ return Visit(ResolveNot(left), right);
1323
+ if (TypeGuard.TNot(right))
1324
+ return Visit(left, ResolveNot(right));
1312
1325
  // Template Literal Union Unwrap
1313
1326
  if (TypeGuard.TTemplateLiteral(left))
1314
1327
  return Visit(TemplateLiteralResolver.Resolve(left), right);
@@ -2077,9 +2090,9 @@ class StandardTypeBuilder extends TypeBuilder {
2077
2090
  Never(options = {}) {
2078
2091
  return this.Create({ ...options, [exports.Kind]: 'Never', not: {} });
2079
2092
  }
2080
- /** `[Standard]` Creates a Not type. The first argument is the disallowed type, the second is the allowed. */
2081
- Not(not, schema, options) {
2082
- return this.Create({ ...options, [exports.Kind]: 'Not', allOf: [{ not: TypeClone.Clone(not, {}) }, TypeClone.Clone(schema, {})] });
2093
+ /** `[Standard]` Creates a Not type */
2094
+ Not(not, options) {
2095
+ return this.Create({ ...options, [exports.Kind]: 'Not', not });
2083
2096
  }
2084
2097
  /** `[Standard]` Creates a Null type */
2085
2098
  Null(options = {}) {
package/value/cast.js CHANGED
@@ -201,7 +201,7 @@ var ValueCast;
201
201
  throw new ValueCastNeverTypeError(schema);
202
202
  }
203
203
  function Not(schema, references, value) {
204
- return check_1.ValueCheck.Check(schema, references, value) ? value : create_1.ValueCreate.Create(schema.allOf[1], references);
204
+ return check_1.ValueCheck.Check(schema, references, value) ? value : create_1.ValueCreate.Create(schema, references);
205
205
  }
206
206
  function Null(schema, references, value) {
207
207
  return check_1.ValueCheck.Check(schema, references, value) ? value : create_1.ValueCreate.Create(schema, references);
package/value/check.js CHANGED
@@ -217,7 +217,7 @@ var ValueCheck;
217
217
  return false;
218
218
  }
219
219
  function Not(schema, references, value) {
220
- return !Visit(schema.allOf[0].not, references, value) && Visit(schema.allOf[1], references, value);
220
+ return !Visit(schema.not, references, value);
221
221
  }
222
222
  function Null(schema, references, value) {
223
223
  return value === null;
package/value/create.d.ts CHANGED
@@ -7,6 +7,10 @@ export declare class ValueCreateNeverTypeError extends Error {
7
7
  readonly schema: Types.TSchema;
8
8
  constructor(schema: Types.TSchema);
9
9
  }
10
+ export declare class ValueCreateNotTypeError extends Error {
11
+ readonly schema: Types.TSchema;
12
+ constructor(schema: Types.TSchema);
13
+ }
10
14
  export declare class ValueCreateIntersectTypeError extends Error {
11
15
  readonly schema: Types.TSchema;
12
16
  constructor(schema: Types.TSchema);
package/value/create.js CHANGED
@@ -27,7 +27,7 @@ THE SOFTWARE.
27
27
 
28
28
  ---------------------------------------------------------------------------*/
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.ValueCreate = exports.ValueCreateRecursiveInstantiationError = exports.ValueCreateDereferenceError = exports.ValueCreateTempateLiteralTypeError = exports.ValueCreateIntersectTypeError = exports.ValueCreateNeverTypeError = exports.ValueCreateUnknownTypeError = void 0;
30
+ exports.ValueCreate = exports.ValueCreateRecursiveInstantiationError = exports.ValueCreateDereferenceError = exports.ValueCreateTempateLiteralTypeError = exports.ValueCreateIntersectTypeError = exports.ValueCreateNotTypeError = exports.ValueCreateNeverTypeError = exports.ValueCreateUnknownTypeError = void 0;
31
31
  const Types = require("../typebox");
32
32
  const check_1 = require("./check");
33
33
  // --------------------------------------------------------------------------
@@ -47,6 +47,13 @@ class ValueCreateNeverTypeError extends Error {
47
47
  }
48
48
  }
49
49
  exports.ValueCreateNeverTypeError = ValueCreateNeverTypeError;
50
+ class ValueCreateNotTypeError extends Error {
51
+ constructor(schema) {
52
+ super('ValueCreate: Not types must have a default value');
53
+ this.schema = schema;
54
+ }
55
+ }
56
+ exports.ValueCreateNotTypeError = ValueCreateNotTypeError;
50
57
  class ValueCreateIntersectTypeError extends Error {
51
58
  constructor(schema) {
52
59
  super('ValueCreate: Intersect produced invalid value. Consider using a default value.');
@@ -215,7 +222,7 @@ var ValueCreate;
215
222
  return schema.default;
216
223
  }
217
224
  else {
218
- return Visit(schema.allOf[1], references);
225
+ throw new ValueCreateNotTypeError(schema);
219
226
  }
220
227
  }
221
228
  function Null(schema, references) {