Skip to content

[DISCUSSION] Flatten exported literal-union unions? #2292

@alexchexes

Description

@alexchexes

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions