Reputation: 2390
I'm trying to create a general function to make routes and validate it with zod in Hono.
When everything is one place, it works okay:
import { zValidator } from "@hono/zod-validator";
import { z, type ZodSchema } from "zod";
import { Hono } from "hono";
const app = new Hono();
const someSchema = z.object({
name: z.string(),
});
app.post("/my-route", zValidator("json", someSchema), async (c) => {
const validated = c.req.valid("json");
// bunch of other things
return c.text("sent");
});
But when I make a separate function for the route:
export const makeRoute = async (c: Context) => {
const validated = c.req.valid("json");
// bunch of other things
return c.text("sent");
};
app.post("/my-route", zValidator("json", someSchema), makeRoute);
Typescript starts to complain about its type Argument of type '"json"' is not assignable to parameter of type 'never'.ts(2345)
:
I guess Context
is not the right type here...
disclaimer: I am a TS noob & am not sure if it's a bug or if I'm doing something wrong.
Upvotes: 0
Views: 301
Reputation: 21
The issue arises because the Context
type in Hono is a generic type with three properties: Env
, Path
, and Input
. When chaining middleware directly in one place, these types are inferred automatically. However, when you separate the route handler into its own function, TypeScript can't infer the types unless you explicitly define them.
To resolve this, you need to define a Context
type that includes the necessary Input
schema for validation.
import { z } from "zod";
import { Context, Env } from "hono";
// Define the schema
const schema = z.object({
name: z.string(),
});
// Define a type for the Input schema
type JsonInputSchema<T extends z.ZodType> = {
in: {
json: z.input<T>;
};
out: {
json: z.infer<T>;
};
};
// Create a generic function for route handlers
function makeRoute<
E extends Env,
P extends string,
I extends JsonInputSchema<typeof schema>
>() {
return async (c: Context<E, P, I>) => {
const validated = c.req.valid("json"); // Validated data
// Perform actions with `validated`
return c.text("sent");
};
}
// Usage example
app.post("/my-route", zValidator("json", schema), makeRoute());
Upvotes: 0