ts-json-schema-generator icon indicating copy to clipboard operation
ts-json-schema-generator copied to clipboard

[DISCUSSION] Flatten exported literal-union unions?

Open alexchexes opened this issue 4 months ago • 7 comments

Hi!

At the moment, when an exported type is a union of other exported literal-only unions, the generator emits a separate definition for each constituent type and then references them from the parent union with anyOf. For example:

export type A = "foo" | "bar";
export type B = "baz" | "quz";

export type C = A | B;

export interface MyObject {
  foo: C;
}

Produces this schema:

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

That output is perfectly valid, but in some situations it would be nicer if C were flattened into a single inline enum, because TypeScript ultimately resolves it to:

type C = "foo" | "bar" | "baz" | "quz";

This case isn't directly covered by the current test suite. My questions are:

  1. Should we keep the existing behaviour and add a test to lock it in?
  2. Or should we change the generator so that, when C is a union of exported literal enums, it merges the literals and inlines them, even though that duplicates the values already present in A and B?
  3. Or should we add an opt-in flag like --flatten-union-literals that performs such flattening only when explicitly requested?

I'm happy to prepare a PR for either approach. What do you think?

alexchexes avatar Jun 23 '25 10:06 alexchexes