honojs / middleware

monorepo for Hono third-party middleware/helpers/wrappers
https://hono.dev
342 stars 120 forks source link

[zod-validator] zValidator type error with param #376

Closed Soulusions closed 5 months ago

Soulusions commented 5 months ago

I am using the zValidator middleware to validate the params in my routes, and I am getting type errors, which strangely didn't happen when I first started writing this code a week back (I think).

Here's how I'm using it:

app.get(
    "/:id",
    zValidator( // <-- Type error here
      "param",
      z.object(
        {
          id: z.string()
        })
    ),
    async (c) => {
// ...

The type error is as follows:

No overload matches this call.
  The last overload gave the following error.
    Argument of type 'MiddlewareHandler<Env, string, { in: { param: { id: string; }; }; out: { param: { id: string; }; }; }>' is not assignable to parameter of type 'H<Env, "/:id", {}, HandlerResponse<any>>'.
      Type 'MiddlewareHandler<Env, string, { in: { param: { id: string; }; }; out: { param: { id: string; }; }; }>' is not assignable to type 'MiddlewareHandler<Env, "/:id", {}>'.
        Types of parameters 'c' and 'c' are incompatible.
          Type 'Context<Env, "/:id", {}>' is not assignable to type 'Context<Env, string, { in: { param: { id: string; }; }; out: { param: { id: string; }; }; }>'.
            Property '#private' in type 'Context' refers to a different member that cannot be accessed from within type 'Context'.
yusukebe commented 5 months ago

Hi @Soulusions

Maybe the file path of the Hono object referenced by zValidator and the Hono object referenced by app are different.

Please share the import statements like:

import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
Soulusions commented 5 months ago

My import statements are the same as yours:

import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
yusukebe commented 5 months ago

@Soulusions

Please try this. It should work:

https://github.com/yusukebe/my-app-zod-validator-example

Soulusions commented 5 months ago

Huh, I don't know why I didn't think of this before, but wiping my node_modules seemingly fixes this, my bad. Javascript hates me...

daniel-lxs commented 4 months ago

I am getting the same error but for json validation

entry.post('/', zValidator('json', createEntryDto), async (c) => {
    const { title, content, ttl, visitCountThreshold, protoHash } =
      c.req.valid('json'); 
}

This is the error:

No overload matches this call.
  The last overload gave the following error.
    Argument of type 'MiddlewareHandler<Env, string, { in: { json: { content: string; ttl: number; visitCountThreshold: number; protoHash: string; title?: string | undefined; }; }; out: { json: { content: string; ttl: number; visitCountThreshold: number; protoHash: string; title?: string | undefined; }; }; }>' is not assignable to parameter of type 'H<Env, "/", BlankInput, HandlerResponse<any>>'.
      Type 'MiddlewareHandler<Env, string, { in: { json: { content: string; ttl: number; visitCountThreshold: number; protoHash: string; title?: string | undefined; }; }; out: { json: { content: string; ttl: number; visitCountThreshold: number; protoHash: string; title?: string | undefined; }; }; }>' is not assignable to type 'MiddlewareHandler<Env, "/", BlankInput>'.
        Types of parameters 'c' and 'c' are incompatible.
          Type 'Context<Env, "/", BlankInput>' is not assignable to type 'Context<Env, string, { in: { json: { content: string; ttl: number; visitCountThreshold: number; protoHash: string; title?: string | undefined; }; }; out: { json: { content: string; ttl: number; visitCountThreshold: number; protoHash: string; title?: string | undefined; }; }; }>'.
            Property '#private' in type 'Context' refers to a different member that cannot be accessed from within type 'Context'.ts(2769)
types.d.ts(152, 5): The last overload is declared here.
yusukebe commented 4 months ago

@daniel-lxs

I am getting the same error but for json validation

Can't reproduce it. I think this is not a bug. If you think it's a bug, please provide a minimal project to reproduce it.

Soulusions commented 4 months ago

Weren't # properties removed in a recent version of hono? I guess you should try to reinstall your node_modules, I'm guessing you have some stray out of date code in there.

himanshu-ntml commented 2 months ago

@yusukebe, here is some more info. thank you so much for great work. Also, I am working on large scale application and thinking to follow below pattern. Any suggestions or inputs?

It doesnt this type error when you add type CONTEXT, (Argument of type 'string' is not assignable to parameter of type 'never'.ts(2345))

import { inject, injectable } from 'tsyringe';
import { BaseController } from '../common/controller';
import { UserService } from './service';

import { Context, Hono } from 'hono';

import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

@injectable()
export class UserController extends BaseController {
  private userService: UserService;

  constructor(@inject(UserService) userService: UserService) {
    super();
    this.userService = userService;
  }

  public setupRoutes(router: Hono): void {
    const idSchema = z.object({
      id: z.string().min(1, 'ID is required'),
    });

    router.get('/users', this.getUsersHandler.bind(this));
    router.get('/users/:id', zValidator('param', idSchema), this.getUserByIdHandler.bind(this));
  }

  private getUsersHandler = async (c: Context) => {
    try {
      const users = await this.userService.getAllUsers();
      return this.jsonResponse(c, users);
    } catch (error) {
      return this.errorResponse(c, 'Failed to fetch users', 500);
    }
  };

  private getUserByIdHandler = async (c: Context) => {
    try {
      const { id } = c.req.valid('param');
      const user = await this.userService.getUserById(id);
      if (!user) {
        return this.errorResponse(c, 'User not found', 404);
      }
      return this.jsonResponse(c, user);
    } catch (error) {
      return this.errorResponse(c, 'Failed to retrieve user', 500);
    }
  };
}

Let me know if you need any more info to debug. I am guessing its type related issue.