Skip to content

feat(cli): infer procedure output type from resolver return type - #112

Merged
KevinEdry merged 1 commit into
mainfrom
feat/infer-output-from-return-type
Jun 18, 2026
Merged

KevinEdry merged 1 commit into
mainfrom
feat/infer-output-from-return-type

Conversation

@KevinEdry

Copy link
Copy Markdown
Owner

Summary

Closes #106.

When a @Query/@Mutation/@Subscription has no explicit output schema, the CLI generator now infers the procedure's output type from the resolver method's return type, instead of falling back to any. This brings nestjs-trpc closer to native tRPC ergonomics and removes the need to duplicate service return types as decorator schemas.

Approach

The generated file imports the router class with import type and casts the placeholder resolver to Awaited<ReturnType<RouterClass["method"]>>:

import type { FolderRouter } from "<...>/folder.router";

list: publicProcedure
  .query(async () => "PLACEHOLDER_DO_NOT_REMOVE" as unknown as Awaited<ReturnType<FolderRouter["list"]>>)

Inference is deferred to the consumer's tsc, so it works through arbitrary business logic and resolves referenced types transitively — the CLI never needs to be a type checker. import type is fully erased, so there's no runtime/bundle impact.

Behavior

  • Explicit output schema always wins — existing behavior is unchanged when output is provided.
  • Inference applies only to named-export routers. Non-exported and default-exported routers fall back to any, since they can't be referenced by name from the generated file.
  • Runtime is unchanged — tRPC already infers output natively at runtime when .output() is omitted; this only closes the codegen gap for the generated AppRouter type.

Tests

  • New output-inference fixture + snapshot covering inferred, explicit-override, and object-literal-return cases.
  • A validation test runs tsc over the generated file to prove the ReturnType<> references compile and types flow through correctly.
  • non-exported-router fixture asserts the any fallback.
  • The validation harness now stubs bare-package modules (e.g. nestjs-trpc) imported by the router files that are now type-checked transitively.

All CLI tests pass; clippy (-D warnings) and rustfmt are clean.

@vercel

vercel Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
nestjs-trpc-docs Ready Ready Preview, Comment Jun 18, 2026 5:52pm

Request Review

When a @Query/@Mutation/@subscription has no explicit `output` schema,
the generator now infers the procedure's output type from the resolver
method's return type via `ReturnType<>`, instead of falling back to
`any`. This brings nestjs-trpc closer to native tRPC ergonomics and
removes the need to duplicate service return types as decorator schemas.

Closes #106

The generated file imports the router class with `import type` and casts
the placeholder resolver to `Awaited<ReturnType<RouterClass["method"]>>`,
deferring inference to the consumer's tsc. This works through arbitrary
business logic and resolves referenced types transitively without the
CLI needing a type checker.

Behavior:
- Explicit `output` schema always takes priority (unchanged).
- Inference only applies to named-export routers; non-exported and
  default-exported routers fall back to `any` since they can't be
  referenced by name from the generated file.
- Runtime is unchanged: tRPC already infers output natively when
  `.output()` is omitted.

Tests:
- New `output-inference` fixture + snapshot covering inferred, explicit-
  override, and object-literal-return cases.
- Validation test runs tsc over the generated file to prove the
  `ReturnType<>` references compile and types flow through.
- `non-exported-router` fixture asserts the `any` fallback.
- Validation harness now stubs bare-package modules (e.g. `nestjs-trpc`)
  imported by the transitively type-checked router files.

Docs:
- Document optional `output` / output inference in routers.mdx, including
  the caveat that inferred return types must be exported/nameable to keep
  the generated AppRouter portable under `declaration: true`.
@KevinEdry
KevinEdry force-pushed the feat/infer-output-from-return-type branch from 77e0947 to d18c1d8 Compare June 18, 2026 17:51
@KevinEdry
KevinEdry merged commit 2c333dc into main Jun 18, 2026
5 checks passed
@KevinEdry
KevinEdry deleted the feat/infer-output-from-return-type branch June 18, 2026 18:22

This branch was successfully deployed

1 active deployment
Preview — d18c1d8b Deployed Jun 18, 2026 by vercel[bot]
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.

Feature request: Infer procedure output types from resolver return type (like native tRPC) when output is not provided

1 participant