vega / ts-json-schema-generator

Generate JSON schema from your Typescript sources
MIT License
1.38k stars 189 forks source link

create schema uses `anyOf` instead of `allOf` #2008

Open george-haroun opened 1 week ago

george-haroun commented 1 week ago

Hello,

Below is an example where interface could be

export type ISchema = ({ foo: string } | { bar: string }) & { baz: string };

Output is

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "anyOf": [
    {
      "additionalProperties": false,
      "properties": {
        "baz": {
          "type": "string"
        },
        "foo": {
          "type": "string"
        }
      },
      "required": [
        "baz",
        "foo"
      ],
      "type": "object"
    },
    {
      "additionalProperties": false,
      "properties": {
        "bar": {
          "type": "string"
        },
        "baz": {
          "type": "string"
        }
      },
      "required": [
        "bar",
        "baz"
      ],
      "type": "object"
    }
  ],
  "definitions": {}
}

I am wondering why not using allOf instead since it's more efficient and easier to understand especially when using any schema validation lib so output could be such as

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "allOf": [
    {
      "additionalProperties": false,
      "properties": {
        "baz": {
          "type": "string"
        }
      },
      "required": [
        "baz"
      ],
      "type": "object"
    },
    {
      "anyOf": [
        {
          "additionalProperties": false,
          "properties": {
            "foo": {
              "type": "string"
            }
          },
          "required": [
            "foo"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "properties": {
            "bar": {
              "type": "string"
            }
          },
          "required": [
            "bar"
          ],
          "type": "object"
        }
      ]
    }
  ],
  "definitions": {}
}

Do you guys have any clue on how to improve this ?

Thanks

domoritz commented 1 week ago

I can't fully recall the details right now but I remember that the semantics of ts and json schema were different so that using allOf with additional properties wasn't semantically equivalent. Try a few examples and may e you find the example I can't recall right now.

arthurfiorette commented 1 week ago

That's right, also a smaller schema is better for any tool that may use it.

However, I thought using references instead of literal types should result into a usage of allOf, but that's not the case:

export type Foo = { foo: string };
export type Baz = { baz: string };
export type Bar = { bar: string };

export type ISchema = (Foo | Bar) & Baz;

results into:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "Bar": {
      "additionalProperties": false,
      "properties": {
        "bar": {
          "type": "string"
        }
      },
      "required": [
        "bar"
      ],
      "type": "object"
    },
    "Baz": {
      "additionalProperties": false,
      "properties": {
        "baz": {
          "type": "string"
        }
      },
      "required": [
        "baz"
      ],
      "type": "object"
    },
    "Foo": {
      "additionalProperties": false,
      "properties": {
        "foo": {
          "type": "string"
        }
      },
      "required": [
        "foo"
      ],
      "type": "object"
    },
    "ISchema": {
      "anyOf": [
        {
          "additionalProperties": false,
          "properties": {
            "baz": {
              "type": "string"
            },
            "foo": {
              "type": "string"
            }
          },
          "required": [
            "baz",
            "foo"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "properties": {
            "bar": {
              "type": "string"
            },
            "baz": {
              "type": "string"
            }
          },
          "required": [
            "bar",
            "baz"
          ],
          "type": "object"
        }
      ]
    }
  }
}

Is that right too, @domoritz?

arthurfiorette commented 1 week ago

Related #67, #62 and #4

domoritz commented 1 week ago

The additional properties false with all of makes the semantics tricky.

arthurfiorette commented 1 week ago

Makes sense. Is the generated schema creating any incompatibilities?