Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Flatten nested unions in `Schema.toJsonSchemaDocument`

Open
#9,533 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
74/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
json, typescript
Domain
backend

Research direction

Read packages/effect/src/internal/schema/toJsonSchemaDocument.ts, especially compileJsonSchema's Union case around the linked lines 611–623, and compare it with the existing nested allOf handling in appendJsonSchema around lines 187–190. Add coverage for nested anyOf output, including members with annotations or $refs and the stated oneOf limitation. Done when eligible nested anyOf members are flattened while other members retain their structure.

Written by the indexing model from the issue text.

Description

What is the problem this feature would solve?

The current output is valid; this is about its shape. Schema.toJsonSchemaDocument writes each member of a Union as one anyOf option, whatever that member is. NullOr of a union, or a union of unions, then comes out as an anyOf inside an anyOf:

import { Schema } from 'effect';

const Person = Schema.Struct({ name: Schema.String });
const Company = Schema.Struct({ company: Schema.String });
const Team = Schema.Struct({ team: Schema.String });

const owner = Schema.NullOr(Schema.Union([Person, Company]));
const member = Schema.Union([Schema.Union([Person, Company]), Team]);

console.log(JSON.stringify(Schema.toJsonSchemaDocument(owner).schema));
console.log(JSON.stringify(Schema.toJsonSchemaDocument(member).schema));

Output (abridged):

{"anyOf":[{"anyOf":[{…name…},{…company…}]},{"type":"null"}]}
{"anyOf":[{"anyOf":[{…name…},{…company…}]},{…team…}]}

The nested form means the same as the flat one, but it's harder to read in rendered docs, and client generators turn it into nested union types.

What is the feature you are proposing to solve the problem?

Write the flat form:

{"anyOf":[{…name…},{…company…},{"type":"null"}]}
{"anyOf":[{…name…},{…company…},{…team…}]}

In the Union case of compileJsonSchema, an anyOf member whose only keyword is anyOf can be replaced by its own members. A member carrying anything else, like an annotation or a $ref to a definition, has to stay as it is:

https://github.com/Effect-TS/effect/blob/7f524e25cfb49a71ac39b0f44278d08d40dda5de/packages/effect/src/internal/schema/toJsonSchemaDocument.ts#L611-L623

appendJsonSchema already splices a nested allOf this way:

https://github.com/Effect-TS/effect/blob/7f524e25cfb49a71ac39b0f44278d08d40dda5de/packages/effect/src/internal/schema/toJsonSchemaDocument.ts#L187-L190

The oneOf mode can't be flattened like this: a value matching every option of { oneOf: [{ oneOf: [a, b] }, c] } is accepted, while { oneOf: [a, b, c] } rejects it.

What alternatives have you considered?

Flattening the output afterwards, in each tool that consumes it. That's being proposed for an OpenAPI converter too, but output used directly, and every other consumer, would stay nested. The same nesting comes from other libraries' JSON Schema output:

  • standard-community/standard-openapi#41
  • open-circle/valibot#1710
  • colinhacks/zod#6673

Version: effect 4.0.5

Dominant language
TypeScript
Stars
16.7k
Forks
808
Avg merge
10h 22m
Merged PRs (30d)
771

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Effect-TS/effect

All issues in Effect-TS/effect

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.