Skip to content

fix(types): preserve macro resolve unions#1903

Open
lxy2500798479 wants to merge 1 commit into
elysiajs:mainfrom
lxy2500798479:fix/macro-union-resolve
Open

fix(types): preserve macro resolve unions#1903
lxy2500798479 wants to merge 1 commit into
elysiajs:mainfrom
lxy2500798479:fix/macro-union-resolve

Conversation

@lxy2500798479

@lxy2500798479 lxy2500798479 commented Jun 1, 2026

Copy link
Copy Markdown

Summary

  • preserve union object values from macro resolve instead of intersecting them into never
  • keep existing intersection behavior for schema/response macro context merging
  • add a regression test for a macro whose resolve returns different object shapes

Fixes #1891

Reproduction

A macro resolve returning { user: { id } } | { user: { id }, admin: true } previously inferred user as never inside the route handler. The new type test verifies user remains { id: string } and admin remains boolean | undefined.

Boundary report

  • scoped to type-level macro context merging only
  • runtime macro behavior unchanged
  • multiple macro resolve fields still merge into one route context
  • schema and response macro merging still use the existing intersection path

Tests

  • bun run test:types
  • bun test test/macro/macro.test.ts
  • bun test
  • bun run test:imports
  • bun run build
  • bun run test:node

Note: bun run test executes test:node without building dist first in this checkout, so test:node fails from missing dist/index.js unless bun run build runs first. After building, bun run test:node passes.

Summary by CodeRabbit

  • Bug Fixes
    • Improved type inference for macros that resolve to unions of different object shapes. Conditional properties are now correctly inferred as optional or required based on whether they appear across all resolved shapes.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d5d92ff0-82ad-4f2e-a4a9-5fd82e3adcae

📥 Commits

Reviewing files that changed from the base of the PR and between 56310be and 98ba2ce.

📒 Files selected for processing (2)
  • src/types.ts
  • test/types/macro.ts

Walkthrough

This PR fixes a type-level regression where macro resolves returning unions of different object shapes were incorrectly inferred as never. The fix introduces type utilities to properly merge object unions and updates macro context inference to preserve union structure for the resolve field.

Changes

Union object merge for macro resolve typing

Layer / File(s) Summary
Union merge type utilities
src/types.ts
Adds UnionKeys, UnionValue, and MergeObjectUnion type utilities to extract union structure and merge object unions into a single object where each property represents the union of values across the input union objects.
Macro context mapping for resolve field
src/types.ts
Modifies InnerMacroToContext to apply MergeObjectUnion to resolve field mapping, replacing the UnionToIntersect behavior that was collapsing union-of-objects to never.
Regression test for resolve union shapes
test/types/macro.ts
Verifies macro with resolve returning { user: { id: 'a' } } | { user: { id: 'b' }, admin: true } correctly types user as { id: string } and admin as boolean | undefined in handler context.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • elysiajs/elysia#1691: Changes to InnerMacroToContext resolve field mapping could impact function-syntax macro overloads that depend on previous macro resolve type inference.

Poem

a union in distress

Union shapes collapsed, you dumb dumb~ ( ´థ౪థ)

Now merged and blessed, perfectly confused♡

Elysia's types are served, arrogantly used ᐡ・ﻌ・ᐡ

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: preserving union types in macro resolve instead of collapsing them to never.
Linked Issues check ✅ Passed The PR fully addresses #1891 by fixing union collapse regression, adding type-level test case, and preserving union-per-property behavior while maintaining intersection semantics for schema/response.
Out of Scope Changes check ✅ Passed All changes are scoped to type-level macro context merging and regression testing; no unrelated runtime modifications or side changes present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/types.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

Error: ESLint configuration in --config » plugin:sonarjs/recommended is invalid:

  • Unexpected top-level property "name".

Referenced from: /.eslintrc.json
at ConfigValidator.validateConfigSchema (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2277:19)
at ConfigArrayFactory._normalizeConfigData (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3123:19)
at ConfigArrayFactory._loadExtendedPluginConfig (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3346:25)
at ConfigArrayFactory._loadExtends (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3259:29)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3199:25)
at _normalizeObjectConfigDataBody.next (<anonym

... [truncated 291 characters] ...

/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2952:16)
at createCLIConfigArray (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3768:35)
(node:2) ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.
(Use node --trace-warnings ... to show where the warning was created)

test/types/macro.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

Error: ESLint configuration in --config » plugin:sonarjs/recommended is invalid:

  • Unexpected top-level property "name".

Referenced from: /.eslintrc.json
at ConfigValidator.validateConfigSchema (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2277:19)
at ConfigArrayFactory._normalizeConfigData (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3123:19)
at ConfigArrayFactory._loadExtendedPluginConfig (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3346:25)
at ConfigArrayFactory._loadExtends (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3259:29)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3199:25)
at _normalizeObjectConfigDataBody.next (<anonym

... [truncated 291 characters] ...

/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2952:16)
at createCLIConfigArray (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3768:35)
(node:2) ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.
(Use node --trace-warnings ... to show where the warning was created)


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

macro resolve returning a union of object shapes infers route context as never (regression in 1.4.25)

1 participant