Skip to content

fix(openapi-typescript): redundant nested unions from type arrays with anyOf/allOf - #2855

Open
sovrin-tio wants to merge 2 commits into
openapi-ts:mainfrom
sovrin-tio:fix_typescript-anyof
Open

fix(openapi-typescript): redundant nested unions from type arrays with anyOf/allOf#2855
sovrin-tio wants to merge 2 commits into
openapi-ts:mainfrom
sovrin-tio:fix_typescript-anyof

Conversation

@sovrin-tio

Copy link
Copy Markdown

Changes

Each member of a type array gets its own recursive transformSchemaObject call, spread
from the full schema object. A sibling anyOf comes along for the ride and gets
transformed inside every member, on top of the top-level pass:

{ "type": ["string","null"], "anyOf": [{"type":"string","format":"ipv4"},{"type":"null"}] }
// before
clientIp?: ((string | null) | null) | string | null;
// after
clientIp?: (string | null) | string | null;

allOf has the same problem. {"type":["string","null"],"allOf":[{"type":"string"}]}
gave ((string) | null) & string, now (string | null) & string.

There are two of these loops, one for schemas with a oneOf and one for everything else.
The oneOf loop already blanked oneOf before recursing but not anyOf/allOf, so
schemas carrying both were still broken. Both loops now call the same
transformTypeMember helper.

How to Review

anyOf/allOf are stripped only for primitive members. Object and array members keep
them: there the composition carries the shape, and stripping leaves
Record<string, never> / unknown[], which widens the union. Tests cover both.

One example line changes, narrower than before:

- [key: string]: (null | (string | number | boolean) | (number | string | boolean) | (boolean | string | number)) | string | number | boolean;
+ [key: string]: (null | string | number | boolean) | string | number | boolean;

The oneOf half changes no example output — no schema in examples/ hits that
combination. Unit-tested only.

Checklist

  • Unit tests updated
  • docs/ updated (if necessary)
  • pnpm run update:examples run (only applicable for openapi-typescript)

…rray recursion

transformSchemaObjectCore spreads the full schema object into each per-type
recursive call, so a sibling anyOf/allOf is transformed once per primitive type
member and again at the top level, yielding redundant nested unions like
((string | null) | null) | string | null.

Extend the existing `oneOf: undefined` guard to anyOf/allOf, but only for
primitive members. object/array members need the composition, since stripping
it collapses the core to Record<string, never> and widens the union.
that branch stripped only oneOf, so a sibling anyOf/allOf still stacked.
Both branches now share one transformTypeMember helper.
@sovrin-tio
sovrin-tio requested a review from a team as a code owner August 26, 2026 14:23
@sovrin-tio
sovrin-tio requested a review from gzm0 August 26, 2026 14:23
@changeset-bot

changeset-bot Bot commented Aug 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f1420f6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
openapi-typescript Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented Aug 26, 2026

Copy link
Copy Markdown

👷 Deploy request for openapi-ts pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit f1420f6

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.

1 participant