Repository navigation
Conversation
InferRouterInputs, InferRouterOutputs, InferRouterInitialContexts, InferRouterFinalContexts, InferRouterError and InferRouterErrors now match a procedure through its `~orpc` definition instead of the Procedure class. They, and UnlaziedRouter, also test each key against AnyRouter before trying the `Lazyable<infer U>` inference, so only lazy keys pay for it. All of them resolve to the same types as before. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VVaw7SLCp5Vav859sAFS6N
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/effect
@orpc/evlog
@orpc/hibernation
@orpc/json-schema
@orpc/experimental-lock
@orpc/mcp
@orpc/msw
@orpc/nest
@orpc/next
@orpc/node
@orpc/openapi
@orpc/opentelemetry
@orpc/pinia-colada
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/swr
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/zod
commit: |
|
No actionable comments were generated in the recent review. Summary
Merge Risk:
|
Merging this PR will improve performance by 62.11%2 warnings
Performance Changes
Tip Curious why performance improved? Comment Comparing Footnotes
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Procedure detection via
~orpc—InferRouterInitialContexts,InferRouterFinalContexts,InferRouterInputs,InferRouterOutputs,InferRouterErrorandInferRouterErrorsnow match a procedure through~orpc: ProcedureDefinition<...>instead of theProcedureclass, so a decorated procedure no longer triggers a structural class comparison. - Router-first key check — those six types plus
UnlaziedRoutertest each key againstAnyRouterbefore falling back to theLazyable<infer U extends AnyRouter>inference, so the inferring union match only runs for lazy keys.
I compared the old and new definitions directly with a throwaway type probe (bare procedure, nested router, Lazy<procedure>/Lazy<router> keys, Lazyable and union keys, optional and readonly keys, AnyRouter, AugmentedRouter output, any, never) and every one of the seven types resolved identically. The branch order is sound: Lazy<T> is not assignable to AnyRouter or to the ~orpc definition shape, so the fast path cannot shadow lazy unwrapping. Root tsc -p tsconfig.json --noEmit is clean.
deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
orpc | 6b959bd | Commit Preview URL Branch Preview URL |
Nov 13 2026, 12:41 AM |

Summary
This applies the same two changes as #2452 to the remaining types that walk a router with
Lazyable<infer U>:InferRouterInputs,InferRouterOutputs,InferRouterInitialContexts,InferRouterFinalContexts,InferRouterErrorandInferRouterErrorsmatch a procedure through its~orpcdefinition instead of theProcedureclass.UnlaziedRouter, test each key againstAnyRouterfirst, which has noinfer. TheLazyable<infer U>inference now runs only for keys that are not plain routers.Every type still recurses on itself; there is no new helper type.
Measurements
The base workload is the
typecheckproject of orpc-benchmarks: 500 routers, 3,000 procedures. Each row replaces its client calls with the lookups described.tsc --singleThreaded --extendedDiagnostics, TypeScript 7.0.2. "Before" is the published2.0.0-beta.50, "after" is@orpc/serverbuilt from this branch. These counts are deterministic.InferRouterInputsandInferRouterOutputs, one lookup per procedure eachInferRouterInitialContexts,InferRouterFinalContextsandInferRouterErrors, one lookup per procedure eachunlazyRouter(), then read by a typed client call per procedureInferRouterErrorhas the same shape asInferRouterErrorsand is changed the same way, but I did not build a separate workload for it.This is independent of #2451, #2452 and #2453.
Behavior
No difference from
main. I compared the old and new definitions of all seven types directly on procedures, nested routers, lazy routers and procedures, keys typed asLazyable<...>, optional and readonly keys,os.router()output,AnyRouter,anyandnever: all resolve to identical types.Emitted declarations are unchanged too. A consumer installed from packed tarballs (pnpm, depending only on
@orpc/server) and built withcomposite: true, including generic code that takes a router as a type parameter, emits a.d.tsbyte-identical to the one built againstmain, on TypeScript 7.0.2, 6.0.3 and 5.9.3.Verification
pnpm check,pnpm test(4,585 tests) andpnpm docs:validatepass. The firstpnpm testrun had two failures inpackages/bun(cancel and abort: bun-fetch), which are runtime timing tests this type-only change cannot reach; they passed in three separate re-runs and in a second full run.Generated by Claude Code