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 }