Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving from 4.7.0 to 4.7.1 throws Object is of type 'unknown'. in hono/client #3976

Open
codercatdev opened this issue Mar 4, 2025 · 6 comments
Labels

Comments

@codercatdev
Copy link

What version of Hono are you using?

4.7.1

What runtime/platform is your app running on? (with version if possible)

Cloudflare Workers

What steps can reproduce the bug?

import type { AppRouter } from "@repo/api";
import { getApiUrl } from "@shared/lib/urls";
import { hc } from "hono/client";

export const apiClient = hc<AppRouter>(getApiUrl(), {
	init: {
		credentials: "include",
	},
}).api;

What is the expected behavior?

No response

What do you see instead?

No response

Additional information

No response

@yusukebe
Copy link
Member

yusukebe commented Mar 5, 2025

Hi @codercatdev

I can't reproduce it. Please share a minimal project to reproduce and an instruction.

@jefer94
Copy link

jefer94 commented Mar 5, 2025

I installed hono@4.7.0 and latest, I tried with turborepo and nx

Image

{
  "compilerOptions": {
    "strict": true,
    "jsx": "react-jsx",
    "jsxImportSource": "hono/jsx"
  }
}
import { Hono } from "hono";
import { upgradeWebSocket } from "hono/cloudflare-workers";
import { z } from "zod";
import { zValidator } from "@hono/zod-validator";
import { hc } from "hono/client";
import type { Client } from "hono/dist/types/client/types";

const PORT = process.env.PORT || process.env.API_PORT || 4000;

const app = new Hono();

app.get("/", (c) => {
  return c.text("Hello Hono!");
});
const schemas = {
  ws: z.object({
    name: z.string(),
    age: z.number(),
  }),
  stuff: z.object({
    key: z.string(),
    value: z.any(),
  }),
};

app.get(
  "/ws",
  // zValidator('query', schemas.ws),
  upgradeWebSocket((c) => {
    const messageSchema = z.object({
      data: z.string(),
    });

    return {
      onMessage(event, ws) {
        const validation = messageSchema.safeParse(event);
        if (!validation.success) {
          console.error("Invalid message format:", validation.error);
          ws.send("Invalid message format");
          return;
        }

        console.log(`Message from client: ${event.data}`);
        ws.send("Hello from server!");
      },
      onClose: () => {
        console.log("Connection closed");
      },
    };
  })
);

type StuffItem = {
  [key: string]: any;
};

let stuff: StuffItem[] = [];

app.get("/stuff", (c) => {
  return c.json(stuff);
});

app.post("/stuff", zValidator("query", schemas.ws), async (c) => {
  const body: StuffItem = await c.req.json();
  stuff.push(body);
  return c.json({ message: "Stuff added successfully", data: body });
});

app.put("/stuff/:id", zValidator("json", schemas.ws), async (c) => {
  const id = parseInt(c.req.param("id"), 10);
  const body: StuffItem = await c.req.json();
  stuff[id] = body;
  return c.json({ message: "Stuff updated successfully", data: body });
});

app.delete("/stuff/:id", (c) => {
  const id = parseInt(c.req.param("id"), 10);
  stuff.splice(id, 1);
  return c.json({ message: "Stuff deleted successfully" });
});

export default {
  port: PORT,
  fetch: app.fetch,
};

export type AppType = typeof app;

const client = hc<typeof app>("http://localhost:4000");

// const client = hc<typeof app>('') as Client<typeof app>;
// // export type Client = typeof client;
client.stuff.$get();

// export const hcWithType = (...args: Parameters<typeof hc>): Client<typeof app> =>
//   hc<typeof app>(...args);

@jefer94
Copy link

jefer94 commented Mar 5, 2025

The functionality is ok, the typing is failing

Image

@yusukebe
Copy link
Member

yusukebe commented Mar 5, 2025

@jefer94 Your code is wrong. Try to the following:

const routes = app
  .get('/stuff', (c) => {
    return c.json(stuff)
  })
  .post('/stuff', zValidator('query', schemas.ws), async (c) => {
    const body: StuffItem = await c.req.json()
    stuff.push(body)
    return c.json({ message: 'Stuff added successfully', data: body })
  })
  .put('/stuff/:id', zValidator('json', schemas.ws), async (c) => {
    const id = parseInt(c.req.param('id'), 10)
    const body: StuffItem = await c.req.json()
    stuff[id] = body
    return c.json({ message: 'Stuff updated successfully', data: body })
  })
  .delete('/stuff/:id', (c) => {
    const id = parseInt(c.req.param('id'), 10)
    stuff.splice(id, 1)
    return c.json({ message: 'Stuff deleted successfully' })
  })

export default {
  port: PORT,
  fetch: app.fetch,
}

export type AppType = typeof routes

const client = hc<AppType>('http://localhost:4000')

@jefer94
Copy link

jefer94 commented Mar 5, 2025

Oh, that typing is working now, is there any way to do this without chaining these calls? maybe the variable name got me confused

Your zValidator is awesome, it could be great to have any way to type the response, working on 4.7.4

@jefer94
Copy link

jefer94 commented Mar 5, 2025

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants