Type Inference
Infer input and output types from your Convex API.
In this guide, we'll explore type inference in cRPC. You'll learn to extract input and output types from your API for use in components, utilities, and type-safe operations.
Overview
cRPC provides type inference utilities similar to tRPC:
| Type | Description |
|---|---|
ApiOutputs | Return types of all procedures |
ApiInputs | Input/argument types of all procedures |
Api | Generated API type |
Let's set it up.
Usage
Access nested procedure types using bracket notation:
import type { ApiInputs, ApiOutputs } from '@convex/api';
// Output types
type User = ApiOutputs['user']['get'];
type UserList = ApiOutputs['user']['list'];
type Post = ApiOutputs['post']['get'];
// Input types
type GetUserArgs = ApiInputs['user']['get'];
type CreatePostArgs = ApiInputs['post']['create'];In Components
Use output types for component props:
import type { ApiOutputs } from '@convex/api';
type User = ApiOutputs['user']['get'];
function UserProfile({ user }: { user: User }) {
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}In Utility Functions
Use both input and output types for type-safe utilities:
import type { ApiInputs, ApiOutputs } from '@convex/api';
type User = ApiOutputs['user']['get'];
type UpdateUserArgs = ApiInputs['user']['update'];
function formatUserName(user: User): string {
return user.name ?? 'Anonymous';
}
function validateUpdateArgs(args: UpdateUserArgs): boolean {
return !!args.name || !!args.email;
}Deep Nested Types
For deeply nested APIs, chain bracket notation:
// api.organization.members.list
type OrgMember = ApiOutputs['organization']['members']['list'][number];
// api.project.settings.get
type ProjectSettings = ApiOutputs['project']['settings']['get'];Tip: Use [number] to extract the item type from array return types.
Migrate from Convex
If you're coming from vanilla Convex, here's what changes.
What stays the same
- Type inference from function definitions
- Full TypeScript support
What's new
Before (vanilla Convex)
import type { FunctionReturnType, FunctionArgs } from 'convex/server';
import { api } from '@convex/_generated/api';
type User = FunctionReturnType<typeof api.user.get>;
type GetUserArgs = FunctionArgs<typeof api.user.get>;After (cRPC)
import type { ApiInputs, ApiOutputs } from '@convex/api';
type User = ApiOutputs['user']['get'];
type GetUserArgs = ApiInputs['user']['get'];Key differences:
| Feature | Description |
|---|---|
| Bracket notation | Cleaner than typeof api.path |
| Centralized types | All definitions in one file |
| Consistent pattern | Same across all procedures |
| Nested namespaces | Works with deep nesting |