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

1 participant