Type coercion does not work with anyOf Number or Boolean
TL;DR: I want a property to support either a boolean OR a number value. With coercion enabled, true will be coerced to 1 or 1 will be coerced to true depending on the order of the types in the anyOf.
What version of Ajv are you using? Does the issue happen if you use the latest version?
0.8.12
Ajv options object
const ajv = new Ajv({ coerceTypes: true })
JSON Schema
const schema = {
type: 'object',
properties: {
foo: { anyOf: [{ type: 'boolean' }, { type: 'number' }] }, // Define boolean first
bar: { anyOf: [{ type: 'number' }, { type: 'boolean' }] }, // Define number first
},
required: ['foo'],
additionalProperties: false,
}
Sample data
const boolData = { foo: true, bar: true } // Results in { foo: true, bar: 1 }
const numData = { foo: 1, bar: 1 } // results in { foo: true, bar: 1 }
What results did you expect?
const boolData = { foo: true, bar: true } // I expect { foo: true, bar: true }
const numData = { foo: 1, bar: 1 } // I expect { foo: 1, bar: 1 }
Since coercion is done according to the order of the types in the schema, the resulting coerced type depends on whether boolean or number comes first, BUT I believe both results are incorrect.
The suggestion from this issue: https://github.com/ajv-validator/ajv/issues/399 would have allowed us to fine tune coercion for this use case, but unfortunately I don't believe the suggestion to use keywords helps us in this case. I tried something similar to what was suggested in the comment in that issue but AJV still coerces the value after the keyword.
There must be something I'm missing here. This seems like a fairly common use case that seems broken. Please advise.
Type coercion is an attempt to apply imperative feature, that depends on order, to declarative schema. So you will indeed be getting different results for different order of coercions, and the options are to expect it or to use type with array of strings instead of anyOf.
Hi @epoberezkin. Thanks for the response. My example here was purposefully simple just to get the point across but our implementation is quite complex, so doing something with an array of strings wouldn't really work. I mostly just wanted validation that keywords do not allow customizing coercion (as suggested in #399) as coercion will still be run after the keyword logic. Our solution for now is to switch to any in our fastify request schema, then later check what the type is supposed to be and do manual validation/coercion against a single type.
So we have found a solution for us, but I would still argue that having overlapping coercion rules with no way to customize the coercion is an issue.
IIRC you can also manage type coercion separately from validation, a solution involving multiple schemas for the two different purposes. In any case I don't see any further action here so I will close it.