Open
Description
Problem description
AJV cannot infer which subtype of a union is being used when creating a union over objects. This might be an issue with AJV core, or just an issue with the error handling.
Below is a simple but complete example of the issue:
import ajvErrors from 'ajv-errors'
import addFormats from 'ajv-formats'
import Ajv, { JSONSchemaType } from 'ajv'
type UploadAction = {
actionType: 'UPLOAD'
url: string
filename: string
}
type EmailAction = {
actionType: 'EMAIL'
email: string
}
type Action = UploadAction | EmailAction
type Actions = Array<Action>
const schema: JSONSchemaType<Actions> = {
type: 'array',
items: {
anyOf: [
{
type: 'object',
required: ['actionType', 'url', 'filename'],
properties: {
actionType: {
type: 'string',
const: 'UPLOAD',
},
url: {
type: 'string',
},
filename: {
type: 'string',
},
},
},
{
type: 'object',
required: ['actionType', 'email'],
properties: {
actionType: {
type: 'string',
const: 'EMAIL',
},
email: {
type: 'string',
},
},
},
],
},
}
if (require.main === module) {
const ajv = new Ajv({ allErrors: true })
ajvErrors(ajv)
addFormats(ajv)
const validate = ajv.compile(schema)
const data: Array<unknown> = [
{
actionType: 'UPLOAD',
},
]
if (validate(data)) {
console.log(data)
} else {
console.log(validate.errors)
}
}
Run this using ts-node
or compile and run it via node. The output I get is
[
{
instancePath: '/0',
schemaPath: '#/items/anyOf/0/required',
keyword: 'required',
params: { missingProperty: 'url' },
message: "must have required property 'url'"
},
{
instancePath: '/0',
schemaPath: '#/items/anyOf/0/required',
keyword: 'required',
params: { missingProperty: 'filename' },
message: "must have required property 'filename'"
},
{
instancePath: '/0',
schemaPath: '#/items/anyOf/1/required',
keyword: 'required',
params: { missingProperty: 'email' },
message: "must have required property 'email'"
},
{
instancePath: '/0/actionType',
schemaPath: '#/items/anyOf/1/properties/actionType/const',
keyword: 'const',
params: { allowedValue: 'EMAIL' },
message: 'must be equal to constant'
},
{
instancePath: '/0',
schemaPath: '#/items/anyOf',
keyword: 'anyOf',
params: {},
message: 'must match a schema in anyOf'
}
]
When I specify actionType: 'UPLOAD'
, I expect that the only missing fields should url
and filename
. The errors output by AJV are confusing and misleading.
In contrast, the typescript type inference engine is correctly able to deduce the the missing fields once the actionType
field is set to one of EMAIL
or UPLOAD
.
Here are my versions via yarn list
:
├─ [email protected]
├─ [email protected]
│ └─ ajv@^8.0.0
├─ [email protected]
│ ├─ fast-deep-equal@^3.1.1
│ ├─ json-schema-traverse@^1.0.0
│ ├─ require-from-string@^2.0.2
│ └─ uri-js@^4.2.2
Metadata
Assignees
Labels
No labels