Skip to content

fix(openapi): preserve event iterator return type in JsonifiedClient - #1797

Merged
dinwwwh merged 2 commits into
middleapi:mainfrom
dinwwwh:claude/issue-1796-8a052e
Aug 7, 2026
Merged

fix(openapi): preserve event iterator return type in JsonifiedClient#1797
dinwwwh merged 2 commits into
middleapi:mainfrom
dinwwwh:claude/issue-1796-8a052e

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Aug 7, 2026

Copy link
Copy Markdown
Member

JsonifiedClient was losing an event iterator's return type: a contract with eventIterator(z.number(), z.number()) produced AsyncIteratorObject<number, any, unknown> instead of a properly typed iterator. AsyncIteratorClass's return(value?: any) signature made TypeScript infer TReturn as any when matched against AsyncIteratorObject<infer U, infer V>, since inference works off actual method signatures rather than the implements clause.

Fixes

  • JsonifiedValue now matches AsyncIteratorClass directly (its own case, ahead of the generic AsyncIteratorObject branch), so the return type inference is no longer poisoned.
  • Jsonified iterator outputs are now typed as AsyncIteratorClass, matching what clients actually receive at runtime.

Testing

  • New type tests cover JsonifiedValue over AsyncIteratorClass and the issue's end-to-end reproduction through JsonifiedClient; all three assertions fail with TReturn = any before the fix and pass after.
  • Root tsc and eslint are clean.

@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
orpc Ready Ready Preview Aug 7, 2026 12:19am

@pkg-pr-new

pkg-pr-new Bot commented Aug 7, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1797

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1797

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@1797

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1797

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@1797

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1797

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@1797

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@1797

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@1797

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1797

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1797

@orpc/next

npm i https://pkg.pr.new/@orpc/next@1797

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1797

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@1797

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@1797

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@1797

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@1797

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@1797

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1797

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1797

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@1797

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1797

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1797

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1797

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1797

commit: a98dbbc

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 25 untouched benchmarks


Comparing dinwwwh:claude/issue-1796-8a052e (a98dbbc) with main (324bd7a)

Open in CodSpeed

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes

  • JsonifiedValue in packages/openapi/src/types.ts now matches AsyncIteratorClass directly (ahead of the structural AsyncIteratorObject branch) and emits AsyncIteratorClass<...> for both iterator flavors, so an event iterator's return type is no longer lost.
  • Added type tests in packages/openapi/src/types.test-d.ts covering JsonifiedValue over AsyncGenerator/AsyncIteratorObject/AsyncIteratorClass plus an end-to-end JsonifiedClient<RouterContractClient<...>> reproduction of the issue.

I verified the change rather than trusting the description: with the fix, root tsc -b is clean; reverting types.ts to the pre-fix logic makes the new assertions fail (the first AsyncIteratorClass branch is load-bearing — dropping it breaks the end-to-end JsonifiedClient assertion at line 55). The new AsyncIteratorClass input branch matters because the asyncIteratorObject(...) schema outputs a concrete AsyncIteratorClass<...> (with private members) that does not satisfy the structural AsyncIteratorObject branch on its own.

The PR body's diagnosis ("TReturn inferred as any from the return(value?: any) signature") is a plausible account of the mechanism; in my reproduction the pre-fix failures surfaced as toEqualTypeOf type-identity mismatches rather than a bare any, but the described symptom and the fix are consistent and correct.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — this run covers commit a98dbbc8 ("improve"), which refines the fix landed in bc8feaa5:

  • JsonifiedValue now returns a flavor-preserving type per input: AsyncIteratorClassAsyncIteratorClass, AsyncGeneratorAsyncGenerator, AsyncIteratorObjectAsyncIteratorObject, with the concrete AsyncIteratorClass case matched first. This is a better version than the previous iteration, which collapsed all iterator outputs into AsyncIteratorClass.
  • Updated types.test-d.ts assertions accordingly and removed the old AsyncGenerator … → AsyncIteratorObject assertion.

Verified on the new head: root tsc -b is clean, and the tests are meaningful — deleting the first AsyncIteratorClass branch makes both the JsonifiedValue<AsyncIteratorClass<…>> and the end-to-end JsonifiedClient assertions (lines 25 and 55) fail, so the branch is load-bearing.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

dinwwwh added a commit that referenced this pull request Aug 7, 2026
…1798)

v1 port of #1797. `JsonifiedClient` was losing an event iterator's
return type: a contract with `eventIterator(z.number(), z.number())`
produced an iterator with `TReturn = any` instead of the jsonified
return type. `AsyncIteratorClass`'s `return(value?: any)` signature made
TypeScript infer `TReturn` as `any` when matched against
`AsyncIteratorObject<infer U, infer V>`, since inference works off
actual method signatures rather than the `implements` clause.

Fixes #1796

## Fixes

- `JsonifiedValue` now matches `AsyncIteratorClass` directly (its own
case, ahead of the generic `AsyncIteratorObject` branch), so the return
type inference is no longer poisoned.
- `AsyncGenerator` and plain `AsyncIteratorObject` values now keep their
own shape instead of being widened, matching the updated #1797.

## Testing

- New type tests cover `JsonifiedValue` over
`AsyncIteratorClass`/`AsyncGenerator`/`AsyncIteratorObject` and the
end-to-end reproduction through `JsonifiedClient` (using v1's
`eventIterator` + `ContractRouterClient`); three assertions fail before
the fix and pass after.
- Root `tsc -b`, `tsc --noEmit`, and eslint are clean.
@dinwwwh
dinwwwh merged commit adde78c into middleapi:main Aug 7, 2026
11 checks passed
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