Skip to Content
Type Inference

Type Inference

Input and output inference is provided by universal types that work for both RPC modules and controller methods.

Client-side inference:

import type { VovkBody, VovkQuery, VovkParams, VovkOutput, VovkIteration, VovkReturnType, VovkYieldType } from 'vovk'; import { UserRPC, StreamRPC } from 'vovk-client'; // infer input type Body = VovkBody<typeof UserRPC.updateUser>; type Query = VovkQuery<typeof UserRPC.updateUser>; type Params = VovkParams<typeof UserRPC.updateUser>; // infer output type Output = VovkOutput<typeof UserRPC.updateUser>; type Iteration = VovkIteration<typeof StreamRPC.streamTokens>; // see below type Return = VovkReturnType<typeof UserRPC.updateUser>; type Yield = VovkYieldType<typeof StreamRPC.streamTokens>;

Server-side inference:

import type { VovkBody, VovkQuery, VovkParams, VovkOutput, VovkIteration, VovkReturnType, VovkYieldType } from 'vovk'; import type UserController from './UserController'; import type StreamController from './StreamController'; // infer input type Body = VovkBody<typeof UserController.updateUser>; type Query = VovkQuery<typeof UserController.updateUser>; type Params = VovkParams<typeof UserController.updateUser>; // infer output type Output = VovkOutput<typeof UserController.updateUser>; type Iteration = VovkIteration<typeof StreamController.streamTokens>; // see below type Return = VovkReturnType<typeof UserController.updateUser>; type Yield = VovkYieldType<typeof StreamController.streamTokens>;

Input Inference

Source types for body, query, and params are defined via VovkRequest<TBody, TQuery, ?TParams>, which specifies the type of the req argument in controller methods. In other words, both raw and validated method definitions determine the input types.

Raw method definition with params as a generic argument:

import type { VovkRequest } from 'vovk'; export default class UserController { @get() static async updateUser(req: VovkRequest<{ email: string }, { id: string }, { param: string }>) { // ... } }

Raw method definition with params as a separate argument:

import type { VovkRequest } from 'vovk'; export default class UserController { @get() static async updateUser(req: VovkRequest<{ email: string }, { id: string }>, params: { param: string }) { // ... } }

Validated methods infer input types automatically:

import { withZod } from 'vovk-zod'; import { z } from 'zod'; export default class UserController { @get() static updateUser = withZod({ query: z.object({ id: z.string() }), params: z.object({ param: z.string() }), body: z.object({ email: z.string().email() }), async handle(req, params) { // ... }, }); }

All three cases generate the same RPC method:

import { UserRPC } from 'vovk-client'; await UserRPC.updateUser({ params: { param: 'value' }, query: { id: 'value' }, body: { email: 'value' }, });

And they allow you to infer input types identically:

import type { VovkBody, VovkQuery, VovkParams } from 'vovk'; import { UserRPC } from 'vovk-client'; type Body = VovkBody<typeof UserRPC.updateUser>; // { email: string } type Query = VovkQuery<typeof UserRPC.updateUser>; // { id: string } type Params = VovkParams<typeof UserRPC.updateUser>; // { param: string }
import type { VovkBody, VovkQuery, VovkParams } from 'vovk'; import type UserController from './UserController'; type Body = VovkBody<typeof UserController.updateUser>; // { email: string } type Query = VovkQuery<typeof UserController.updateUser>; // { id: string } type Params = VovkParams<typeof UserController.updateUser>; // { param: string }

Output/Iteration Inference

Output and iteration types are defined only when using validation libraries.

For output:

import { withZod } from 'vovk-zod'; import { z } from 'zod'; export default class UserController { @get() static updateUser = withZod({ output: z.object({ success: z.boolean() }), async handle(req, params) { return { success: true }; }, }); }

For JSON Lines responses:

import { withZod } from 'vovk-zod'; import { z } from 'zod'; export default class StreamController { @get() static streamItems = withZod({ iteration: z.object({ item: z.boolean() }), async *handle(req, params) { yield { item: true }; yield { item: true }; }, }); }
import type { VovkOutput, VovkIteration } from 'vovk'; import { UserRPC } from 'vovk-client'; type Output = VovkOutput<typeof UserRPC.updateUser>; // { success: boolean } type Iteration = VovkIteration<typeof StreamRPC.streamItems>; // { item: boolean }
import type { VovkOutput, VovkIteration } from 'vovk'; import type UserController from './UserController'; import type StreamController from './StreamController'; type Output = VovkOutput<typeof UserController.updateUser>; // { success: boolean } type Iteration = VovkIteration<typeof StreamController.streamItems>; // { item: boolean }

Return/Yield Inference

VovkReturnType<T> and VovkYieldType<T> infer the actual return or yield type of methods when input is not validated. These types cannot be used for self-references in services, as they cause “implicit any” TypeScript errors.

export default class UserController { @get() static updateUser = () => { return { success: true }; } }
export default class StreamController { @get() static async *streamItems() { yield { item: true }; yield { item: true }; } }
import type { VovkReturnType, VovkYieldType } from 'vovk'; import { UserRPC, StreamRPC } from 'vovk-client'; type Return = VovkReturnType<typeof UserRPC.updateUser>; // { success: boolean } type Yield = VovkYieldType<typeof StreamRPC.streamItems>; // { item: boolean }
import type { VovkReturnType, VovkYieldType } from 'vovk'; import type UserController from './UserController'; import type StreamController from './StreamController'; type Return = VovkReturnType<typeof UserController.updateUser>; // { success: boolean } type Yield = VovkYieldType<typeof StreamController.streamItems>; // { item: boolean }
Last updated on