Skip to content

Commit 9581bcc

Browse files
authored
feat(client): infer utilities (#1096)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced client type-inference utilities for inputs, body inputs, outputs, body outputs, error maps, and aggregated error unions for oRPC clients. No runtime changes. * **Documentation** * Added a "Utilities" section to client docs with descriptions and code examples for the new inference helpers. * **Tests** * Added type-level tests validating the new inference utilities. * **Chores** * Expanded public type surface without breaking existing APIs. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent bf27b66 commit 9581bcc

File tree

15 files changed

+259
-15
lines changed

15 files changed

+259
-15
lines changed

β€ŽREADME.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ This is a quick overview of how to use oRPC. For more details, please refer to t
211211
oRPC is inspired by existing solutions that prioritize type safety and developer experience. Special acknowledgments to:
212212

213213
- [tRPC](https://trpc.io): For pioneering the concept of end-to-end type-safe RPC and influencing the development of type-safe APIs.
214-
- [ts-rest](https://ts-rest.com): For its emphasis on contract-first development and OpenAPI integration, which have greatly inspired oRPC’s feature set.
214+
- [ts-rest](https://ts-rest.com): For its emphasis on contract-first development and OpenAPI integration, which have greatly inspired oRPC's feature set.
215215

216216
## License
217217

β€Žapps/content/docs/adapters/browser.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ clientPort.start()
8787

8888
## Advanced Relay Pattern
8989

90-
In some advanced cases, direct communication between scripts isn’t possible. For example, a content script running in the ["MAIN" world](https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts#world-timings) cannot directly communicate with the background script using `browser.runtime` or `chrome.runtime` APIs.
90+
In some advanced cases, direct communication between scripts isn't possible. For example, a content script running in the ["MAIN" world](https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts#world-timings) cannot directly communicate with the background script using `browser.runtime` or `chrome.runtime` APIs.
9191

9292
To work around this, you can use a **relay pattern** typically an additional content script running in the default **"ISOLATED" (default) world** to relay messages between the two contexts. This **relay pattern** acts as an intermediary, enabling communication where direct access is restricted.
9393

β€Žapps/content/docs/best-practices/optimize-ssr.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ But how? A naive `typeof window === 'undefined'` check works, but exposes your r
3535

3636
## Implementation
3737

38-
We’ll use `globalThis` to share the server client without bundling it into client code.
38+
We'll use `globalThis` to share the server client without bundling it into client code.
3939

4040
::: code-group
4141

β€Žapps/content/docs/client/client-side.mdβ€Ž

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,103 @@ export const orpc = {
9797
c: clientC,
9898
}
9999
```
100+
101+
## Utilities
102+
103+
::: info
104+
These utilities can be used for any kind of oRPC client.
105+
:::
106+
107+
### Infer Client Inputs
108+
109+
```ts twoslash
110+
import type { orpc as client } from './shared/planet'
111+
// ---cut---
112+
import type { InferClientInputs } from '@orpc/client'
113+
114+
type Inputs = InferClientInputs<typeof client>
115+
116+
type FindPlanetInput = Inputs['planet']['find']
117+
```
118+
119+
Recursively infers the **input types** from a client. Produces a nested map where each endpoint's input type is preserved.
120+
121+
### Infer Client Body Inputs
122+
123+
```ts twoslash
124+
import type { orpc as client } from './shared/planet'
125+
// ---cut---
126+
import type { InferClientBodyInputs } from '@orpc/client'
127+
128+
type BodyInputs = InferClientBodyInputs<typeof client>
129+
130+
type FindPlanetBodyInput = BodyInputs['planet']['find']
131+
```
132+
133+
Recursively infers the **body input types** from a client. If an endpoint's input includes `{ body: ... }`, only the `body` portion is extracted. Produces a nested map of body input types.
134+
135+
### Infer Client Outputs
136+
137+
```ts twoslash
138+
import type { orpc as client } from './shared/planet'
139+
// ---cut---
140+
import type { InferClientOutputs } from '@orpc/client'
141+
142+
type Outputs = InferClientOutputs<typeof client>
143+
144+
type FindPlanetOutput = Outputs['planet']['find']
145+
```
146+
147+
Recursively infers the **output types** from a client. Produces a nested map where each endpoint's output type is preserved.
148+
149+
### Infer Client Body Outputs
150+
151+
```ts twoslash
152+
import type { orpc as client } from './shared/planet'
153+
// ---cut---
154+
import type { InferClientBodyOutputs } from '@orpc/client'
155+
156+
type BodyOutputs = InferClientBodyOutputs<typeof client>
157+
158+
type FindPlanetBodyOutput = BodyOutputs['planet']['find']
159+
```
160+
161+
Recursively infers the **body output types** from a client. If an endpoint's output includes `{ body: ... }`, only the `body` portion is extracted. Produces a nested map of body output types.
162+
163+
### Infer Client Errors
164+
165+
```ts twoslash
166+
import type { orpc as client } from './shared/planet'
167+
// ---cut---
168+
import type { InferClientErrors } from '@orpc/client'
169+
170+
type Errors = InferClientErrors<typeof client>
171+
172+
type FindPlanetError = Errors['planet']['find']
173+
```
174+
175+
Recursively infers the **error types** from a client when using [type-safe error handling](/docs/error-handling#type‐safe-error-handling). Produces a nested map where each endpoint's error type is preserved.
176+
177+
### Infer Client Error Union
178+
179+
```ts twoslash
180+
import type { orpc as client } from './shared/planet'
181+
// ---cut---
182+
import type { InferClientErrorUnion } from '@orpc/client'
183+
184+
type AllErrors = InferClientErrorUnion<typeof client>
185+
```
186+
187+
Recursively infers a **union of all error types** from a client when using [type-safe error handling](/docs/error-handling#type‐safe-error-handling). Useful when you want to handle all possible errors from any endpoint at once.
188+
189+
### Infer Client Context
190+
191+
```ts twoslash
192+
import type { orpc as client } from './shared/planet'
193+
// ---cut---
194+
import type { InferClientContext } from '@orpc/client'
195+
196+
type Context = InferClientContext<typeof client>
197+
```
198+
199+
Infers the client context type from a client.

β€Žapps/content/docs/client/rpc-link.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const client: RouterClient<typeof router> = createORPCClient(link)
4343

4444
## Using Client Context
4545

46-
Client context lets you pass extra information when calling procedures and dynamically modify RPCLink’s behavior.
46+
Client context lets you pass extra information when calling procedures and dynamically modify RPCLink's behavior.
4747

4848
```ts twoslash
4949
import { router } from './shared/planet'

β€Žapps/content/docs/context.mdβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Understanding context in oRPC
55

66
# Context in oRPC
77

8-
oRPC’s context mechanism provides a type-safe dependency injection pattern. It lets you supply required dependencies either explicitly or dynamically through middleware. There are two types:
8+
oRPC's context mechanism provides a type-safe dependency injection pattern. It lets you supply required dependencies either explicitly or dynamically through middleware. There are two types:
99

1010
- **Initial Context:** Provided explicitly when invoking a procedure.
1111
- **Execution Context:** Generated during procedure execution, typically by middleware.
@@ -80,7 +80,7 @@ const getting = base.handler(async ({ context }) => {
8080
export const router = { getting }
8181
```
8282

83-
When using execution context, you don’t need to pass any context manually:
83+
When using execution context, you don't need to pass any context manually:
8484

8585
```ts twoslash
8686
import { os } from '@orpc/server'

β€Žapps/content/docs/contract-first/implement-contract.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const os = implement(contract) // fully replaces the os from @orpc/server
4747

4848
## Implementing Procedures
4949

50-
Define a procedure by attaching a `.handler` to its corresponding contract, ensuring it adheres to the contract’s specifications.
50+
Define a procedure by attaching a `.handler` to its corresponding contract, ensuring it adheres to the contract's specifications.
5151

5252
```ts twoslash
5353
import { contract } from './shared/planet'

β€Žapps/content/docs/error-handling.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Do not pass sensitive data in the `ORPCError.data` field.
4848

4949
## Type‑Safe Error Handling
5050

51-
For a fully type‑safe error management experience, define your error types using the `.errors` method. This lets the client infer the error’s structure and handle it accordingly. You can use any [Standard Schema](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec) library to validate error data.
51+
For a fully type‑safe error management experience, define your error types using the `.errors` method. This lets the client infer the error's structure and handle it accordingly. You can use any [Standard Schema](https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec) library to validate error data.
5252

5353
```ts twoslash
5454
import { os } from '@orpc/server'

β€Žapps/content/docs/integrations/pinia-colada.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Seamlessly integrate oRPC with Pinia Colada
55

66
# Pinia Colada Integration
77

8-
[Pinia Colada](https://pinia-colada.esm.dev/) is the data fetching layer for Pinia and Vue. oRPC’s integration with Pinia Colada is lightweight and straightforward - there’s no extra overhead.
8+
[Pinia Colada](https://pinia-colada.esm.dev/) is the data fetching layer for Pinia and Vue. oRPC's integration with Pinia Colada is lightweight and straightforward - there's no extra overhead.
99

1010
::: warning
1111
This documentation assumes you are already familiar with [Pinia Colada](https://pinia-colada.esm.dev/). If you need a refresher, please review the official Pinia Colada documentation before proceeding.

β€Žapps/content/docs/integrations/tanstack-query-old/basic.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Seamlessly integrate oRPC with Tanstack Query
55

66
# Tanstack Query Integration
77

8-
[Tanstack Query](https://tanstack.com/query/latest) is a robust solution for asynchronous state management. oRPC’s integration with Tanstack Query is lightweight and straightforward - there’s no extra overhead.
8+
[Tanstack Query](https://tanstack.com/query/latest) is a robust solution for asynchronous state management. oRPC's integration with Tanstack Query is lightweight and straightforward - there's no extra overhead.
99

1010
| Library | Tanstack Query | oRPC Integration |
1111
| ------- | -------------- | ------------------------- |

0 commit comments

Comments
Β (0)