Shahriar
Shahriar

Reputation: 2390

Hono Zod Argument of type '"json"' is not assignable to parameter of type 'never'

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):

enter image description here

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

Answers (1)

Aditya Mathur
Aditya Mathur

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

Related Questions