JSON X-Type is a data type format for describing JSON-like structures in a simple and natural way. Any valid JSON can be validated against a JSON X-Type definition.
JSON X-Type can be described by itself (🔗).
Keyword | Description | Usage |
---|---|---|
string | String type. | key, value |
number | Number type. | value |
boolean | Boolean type. | value |
null |
The null value. (Note: The string "null" has no special meaning.) |
value |
undefined | Indicates that the value is not set. | value |
array | Array generic. | key |
any | Any value (not validated). | value |
$and (🔗) | Represents the combination of array members. | key |
$ref (🔗) | Reference to another JSON X-Type. | key* |
The list can be extended with other $
-prefixed keywords.
So it's a good idea to escape any custom keys that start with $
using the $literal
prefix (🔗).
Object literals define object-like schemas:
{
"name": "string",
"age": "number"
}
The example above defines an object with two required properties.
It's also possible to use the string
type as a key to describe records:
{
"string": "boolean"
}
Array literals define multiple options, one of which is applicable:
["string", "undefined"]
It is possible to combine several types into one using the $and
keyword:
{
"$and": [{"foo": "string"}, {"bar": "number"}]
}
The result is an object that includes all of the properties of all the items:
{
"foo": "string",
"bar": "number"
}
A TypeScript analogy of the $and
operator is the following:
type And<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never
type Combined = And<{foo: string} | {bar: number}> // {"foo": "string"} & {"bar": "number"} ≡ {"foo": "string", "bar": "number"}
Effectively, it applies the AND
relation between the array members, replacing the OR
relation.
Note that it doesn't make sense to combine primitive types or objects that have common properties with different types:
{
"$and": [{"foo": "string"}, {"foo": "number"}]
}
The above example results in foo
being both string
and number
, which is effectively equivalent to TypeScript's never
type.
Impossible combinations should result in the undefined
type.
Whenever there is a need to use a literal string value instead of a reserved keyword, it must be prepended with the $literal:
prefix:
{
"$literal:string": "boolean"
}
This checks for an object with the string
key of a boolean
value, e.g.:
{
"string": true
}
It is possible to refer to other JSON X-Types using the JSON Pointer syntax:
{
"foo": {"$ref": "#/bar"},
"bar": ["string", "number", "boolean"]
}
A reference must be resolved relative to the file it appears in.
The $ref
expression must be replaced with the value of the field it refers to.
Any other properties alongside the $ref
must be ignored.
Alternatively, the $ref
keyword can be used as a prefix, which is easier to write and read (though support depends on the implementation):
{
"foo": "$ref:./path/to/file"
}
If a reference cannot be resolved, it should be treated as any
.
Possible extensions are described here.