You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `Type.Not` was first introduced in Revision 0.26.0. This type accepted two arguments, the first is the `not` type, the second is the `allowed` type. In 0.26.0, TypeBox would treat the `allowed` type as the inferred type with the schema represented in the following form.
@@ -81,11 +90,13 @@ const T = {
81
90
//
82
91
typeT=Static<typeofT> // type T = number
83
92
```
84
-
The 0.29.0 `Not` type properly represents the JSON Schema `not` keyword in its simplest form, as well as making better use of the type intersection narrowing capabilities of TypeScript with respect to inference.
93
+
The 0.29.0 `Not` type properly represents the JSON Schema `not` keyword in its simplest form, as well as making better use of intersection type narrowing capabilities of TypeScript.
85
94
86
-
### Invert Not
95
+
<a name="Not-Inversion"></a>
87
96
88
-
In revision 0.29.0, it is possible to invert the `Not` type. TypeBox will track each inversion and statically infer appropriately.
97
+
## Not Inversion
98
+
99
+
The not type can be inverted through nesting.
89
100
90
101
```typescript
91
102
// not not string
@@ -105,4 +116,29 @@ const T = {
105
116
// inferred as
106
117
//
107
118
typeT=Static<typeofT> // type T = string
108
-
```
119
+
```
120
+
121
+
<a name="Inference-Limitations"></a>
122
+
123
+
## Inference Limitations
124
+
125
+
Not types are synonymous with the concept of [negated types](https://github.com/microsoft/TypeScript/issues/4196) which are not supported in the TypeScript language. Because of this, it is not currently possible to infer negated types in a way one would naturally expect for some cases. Consider the following.
126
+
127
+
```typescript
128
+
const T =Type.Intersect([Type.String(), Type.Not(Type.String())])
129
+
130
+
typeT=Static<typeofT> // type T = string & not string
131
+
// actual: string
132
+
// expect: never
133
+
```
134
+
As such, the use of Not types should be used with some consideration to current limitations, and reserved primarily for narrowing cases such as the following.
135
+
136
+
```typescript
137
+
const T =Type.Intersect([Type.String(), Type.Not(Type.Literal('disallowed string'))])
138
+
139
+
typeT=Static<typeofT> // type T = string & not 'disallowed string'
Copy file name to clipboardExpand all lines: readme.md
+11-9
Original file line number
Diff line number
Diff line change
@@ -888,14 +888,16 @@ const C = Type.Index(T, Type.KeyOf(T)) // const C = {
888
888
889
889
### Not Types
890
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 Not types are not supported in TypeScript, but can still be partially expressed by interpreting `not` as the broad type `unknown`. When used in intersections, the Not type can be used to create refined assertion rules for specific types, with the inference derived from TypeScript's ability to narrow from `unknown` to `T` via 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.
891
+
TypeBox has partial support for the JSON schema `not` keyword with `Type.Not`. This type is synonymous with the concept of a [negated types](https://github.com/microsoft/TypeScript/issues/4196) which are not supported in the TypeScript language. TypeBox does provide partial inference support via the intersection of `T¬U` (where all negated types infer as `unknown`). This can be used in the following context.
894
892
895
893
```typescript
896
-
//Pseudo TypeScript
894
+
// TypeScript
897
895
898
-
typeT=number¬ (1|2|3) // allow all numbers except 1, 2, 3
896
+
typeT=Exclude<number, 1|2|3>// all numbers except 1, 2, 3
897
+
//
898
+
// ideally expressed as:
899
+
//
900
+
// type T = number & not (1 | 2 | 3)
899
901
900
902
// TypeBox
901
903
@@ -914,11 +916,11 @@ const T = Type.Intersect([ // const T = {
914
916
// ]
915
917
// }
916
918
917
-
typeT=Static<typeofT>//evaluates as:
919
+
typeT=Static<typeofT>//inferred:
918
920
//
919
-
// type T = (number & (not (1 | 2 | 3)))
920
-
// type T = (number & (unknown))
921
-
// type T = (number)
921
+
// type T = number & not (1 | 2 | 3)
922
+
// type T = number & unknown
923
+
// type T = number
922
924
```
923
925
924
926
The Not type can be used with constraints to define schematics for types that would otherwise be difficult to express.
0 commit comments