ajv: Limitation: JSONSchemaType does not support unions

What version of Ajv are you using? Does the issue happen if you use the latest version?

ajv@7.0.0-beta.1

Ajv options object

N/A (type error)

JSON Schema

See code below

Sample data

N/A (type error)

Your code

type VariableGroupValue = string | number | { query: string };

const variableGroupValueSchema: JSONSchemaType<VariableGroupValue> = {
  anyOf: [
    {
      type: 'string',
    },
    {
      type: 'number',
    },
    {
      type: 'object',
      properties: {
        query: {
          type: 'string',
        },
      },
      required: ['query'],
      additionalProperties: false,
    },
  ],
};

Validation result, data AFTER validation, error messages

const variableGroupValueSchema: JSONSchemaType<VariableGroupValue, false>
Type '{ anyOf: ({ type: "string"; } | { type: "number"; } | { type: "object"; properties: { query: { type: "string"; }; }; required: "query"[]; additionalProperties: false; })[]; }' is not assignable to type 'JSONSchemaType<VariableGroupValue, false>'.
  Type '{ anyOf: ({ type: "string"; } | { type: "number"; } | { type: "object"; properties: { query: { type: "string"; }; }; required: "query"[]; additionalProperties: false; })[]; }' is not assignable to type '{ type: "object"; required: "query"[]; additionalProperties: boolean; properties?: PropertiesSchema<{ query: string; }> | undefined; patternProperties?: { [pattern: string]: never; } | undefined; propertyNames?: JSONSchemaType<...> | undefined; dependencies?: { ...; } | undefined; minProperties?: number | undefined;...'.
    Type '{ anyOf: ({ type: "string"; } | { type: "number"; } | { type: "object"; properties: { query: { type: "string"; }; }; required: "query"[]; additionalProperties: false; })[]; }' is missing the following properties from type '{ type: "object"; required: "query"[]; additionalProperties: boolean; properties?: PropertiesSchema<{ query: string; }> | undefined; patternProperties?: { [pattern: string]: never; } | undefined; propertyNames?: JSONSchemaType<...> | undefined; dependencies?: { ...; } | undefined; minProperties?: number | undefined;...': type, required, additionalPropertiests(2322)
Peek Problem (Alt+F8)
No quick fixes available

image

It complains that the top level schema object doesn’t have the keys: type, required, additionalPropertiests. I thought I could use anyOf on it’s own. It doesn’t really make sense to use type at the top level because it could be one of three different types but it looks like it expects it to be an object. I also tried oneOf with the same result.

Any suggestions or workarounds welcome, especially if my schema is wrong. Thanks

What results did you expect?

Expected no type error

Are you going to resolve the issue?

No.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 5
  • Comments: 17 (9 by maintainers)

Commits related to this issue

Most upvoted comments

in v8

not all types have the same extra parameters, correct? So for a native string | number you might do type: [“string”, “number”] but you might use anyOf if you wanted only positive numbers. In this case, both should potentially type check?

Yes

as unions of all possible ways to divide them up seem hard.

Yes, that’s why I didn’t do it 😃 There are plenty of edge cases and somewhere the line should be drawn.

JSONDataType might actually be easier

Interesting 😃

Does that make sense and sound reasonable?

Yes. I am very happy with any limitations tbh - I would just add them to the docs. JSONSchemaType is not comprehensive as is anyway, it only highlights how difficult it is to map JSON Schema to types (in general case)

I’ve looked into this a bit, and there’s a problem.

The current implementation takes the stance that JSONSchemaType<A | B> = JSONSchemaType<A> | JSONSchemaType<B>

This property is used to create the SomeJSONSchema type by calling JSONSchemaType<Known> where Known represents a union of all possible types. I don’t see a way to address unions properly without breaking this.

Note, you can kind of specify unions, you just need to have a fully defined root object, and then define partial schema off of it. It won’t work for everything, but there might be clever ways to make some things wok, e.g. you can’t represent JSONSchemaType<string | number> but you can do:

type B = { b: number }
type C = { b: string }

const x: JSONSchemaType<B | C> = {
    type: "object",
    required: ["b"],
    anyOf: [
        { properties: { b: { type: "number" } } },
        { properties: { b: { type: "string" } } },
    ]
}

@erikbrinkman not sure you’ve seen it. Somebody on Gitter also just asked for it (not sure if you are there). I was planning to look at it some time in April, not sooner - if you could help improve JSONSchemaType before that lots of people would be happy (including myself obviously:)

This JSONSchemaType<T> type doesn’t support unions yet, so just use a generic Schema (or SchemaObject) type.

You can still compile schemas into type guards with type parameters