Skip to content

fix: dereference alias types in discriminated unions (#1750)#2420

Open
CristianLopezR wants to merge 2 commits into
vega:nextfrom
CristianLopezR:fix/issue-1750-alias-discriminator
Open

fix: dereference alias types in discriminated unions (#1750)#2420
CristianLopezR wants to merge 2 commits into
vega:nextfrom
CristianLopezR:fix/issue-1750-alias-discriminator

Conversation

@CristianLopezR

Copy link
Copy Markdown

This PR fixes issue #1750.

Previously, getJsonSchemaDiscriminatorDefinition failed to identify literal types when they were wrapped in a Type Alias (e.g., type MyKind = "kind_a").

This change adds a derefType() step when retrieving the discriminator property type in UnionTypeFormatter.ts, ensuring the underlying literal value is correctly extracted.

Fixes #1750

@arthurfiorette arthurfiorette self-assigned this Dec 3, 2025

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes discriminated-union discriminator extraction when the discriminator property type is wrapped (e.g., via exported type aliases), by dereferencing the discriminator property type before generating if/then branches.

Changes:

  • Dereference discriminator property types in UnionTypeFormatter.getJsonSchemaDiscriminatorDefinition() to correctly extract underlying literal values.
  • Add a new valid-data fixture and test case intended to cover alias-type dereferencing for discriminated unions.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/TypeFormatter/UnionTypeFormatter.ts Dereferences discriminator property type before definition generation.
test/valid-data/dereference-alias-types-discriminated-unions/main.ts Adds a TypeScript fixture with alias-based discriminator property types.
test/valid-data/dereference-alias-types-discriminated-unions/schema.json Adds the expected schema output for the new fixture.
test/valid-data/dereference-alias-types-discriminated-unions/index.test.ts Registers the new valid-data schema assertion test.
Comments suppressed due to low confidence (1)

src/TypeFormatter/UnionTypeFormatter.ts:55

  • kindTypes is built from a filtered type.getTypes() list (excluding types that deref to NeverType), but the error message uses type.getTypes()[undefinedIndex] from the unfiltered list. If any union member dereferences to NeverType, the index can point at the wrong member type in the error. Consider keeping a const filteredTypes = ... array and using it consistently for both kindTypes and error reporting.
        const kindTypes = type
            .getTypes()
            .filter((item) => !(derefType(item) instanceof NeverType))
            .map((item) => {
                const propertyType = getTypeByKey(item, new LiteralType(discriminator));

                return propertyType ? derefType(propertyType) : undefined;
            });

        const undefinedIndex = kindTypes.findIndex((item) => item === undefined);

        if (undefinedIndex !== -1) {
            throw new JsonTypeError(
                `Cannot find discriminator keyword "${discriminator}" in type ${type.getTypes()[undefinedIndex].getName()}.`,
                type,
            );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +13 to +14

export type MyUnion = ObjectA | ObjectB;

Copilot AI Feb 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixture is named/used as a discriminated-union regression test, but MyUnion is not annotated with @discriminator kind, so UnionTypeFormatter.getJsonSchemaDiscriminatorDefinition() (and the new deref logic) will never run. Add a JSDoc @discriminator kind on MyUnion to actually exercise the discriminated-union code path.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is right, the PR attempts to fix discriminated unions but your union is not discriminated

Comment on lines +5 to +7
"MyUnion": {
"anyOf": [
{

Copilot AI Feb 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is meant to validate discriminated-union output, the expected schema should reflect the @discriminator handling (i.e., a definitions.MyUnion object with allOf containing if/then branches and a discriminator properties.kind.enum). The current expected schema is a plain anyOf of the variants, which does not exercise getJsonSchemaDiscriminatorDefinition() or the new dereferencing behavior.

Copilot uses AI. Check for mistakes.
Comment thread src/TypeFormatter/UnionTypeFormatter.ts
@@ -0,0 +1,14 @@
type KindA = "kind_a";
type KindB = "kind_b";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if you export KindB? will it keep being a reference instead of inlining like

{
                            "const": "kind_a",
                            "type": "string"
                        },

?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate (nested) discriminator union values not allowed

3 participants