H
Hono4w ago
wyrd

Why does .openapi(route, handler) return unknown type in client.ts when using OpenAPIHono?

I’m new to Hono and trying out @hono/zod-openapi for the first time. Im trying out the RPC feature with client.ts I noticed that when I define my routes like this
const app = new OpenAPIHono()
app.openapi(getTodosRoute, (c) => {
// handler logic
})
const app = new OpenAPIHono()
app.openapi(getTodosRoute, (c) => {
// handler logic
})
client is type unkown But when I chain the .openapi(...) calls like this:
const app = new OpenAPIHono()
.openapi(getTodosRoute, async (c) => { /* handler */ })
.openapi(getTodoByIdRoute, async (c) => { /* handler */ })
const app = new OpenAPIHono()
.openapi(getTodosRoute, async (c) => { /* handler */ })
.openapi(getTodoByIdRoute, async (c) => { /* handler */ })
the types are inferred correctly in client.ts. Why is there a difference? Is this expected behavior with OpenAPIHono, or am I missing something in how route types are collected? Here is my full code https://pastebin.com/dyeYHung
Pastebin
Hono - Pastebin.com
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
4 Replies
Arjix
Arjix4w ago
Unrelated to openapi/zod/hono This is fundamental typescript design Typescript types are immutable, if you don't chain your calls, then the type of app doesn't have the routes in it's context Every time you do .get/.post/.openapi, you create a new typescript type, and you are not saving it to a variable, so it's gone Basically
const a = 5;
a + 1;
a + 2;
a - 1;

console.log(a)
const a = 5;
a + 1;
a + 2;
a - 1;

console.log(a)
What does that print? If you are confused by this, you gotta realize that typescript types are a language on their own. Chaining would be
const a = 5 + 1 + 2 - 1;
console.log(a);
const a = 5 + 1 + 2 - 1;
console.log(a);
I hope that helps visualize the difference To gain a deeper understanding, you can look at functional languages like ocaml, because the type system is a functional language
wyrd
wyrdOP4w ago
I see so chaining is the right way ? I see i dont have to
const app = new OpenAPIHono()
app.openapi(getTodosRoute, (c) => {
// handler logic
})
const app = new OpenAPIHono()
app.openapi(getTodosRoute, (c) => {
// handler logic
})
I can just do
const app = new OpenAPIHono()
.openapi(getTodosRoute, (c) => {
// handler logic
})
const app = new OpenAPIHono()
.openapi(getTodosRoute, (c) => {
// handler logic
})
Arjix
Arjix4w ago
Honestly, it depends. If your API is super small, then yes it's great. But if your API is huge, you'll face issues with the typescript type inference. You may want to export individual types of your API and have multiple RPCs. Personally I don't use the RPC at all, so I don't chain at all. But yeah, chaining is the right way. This is not necessarily a disadvantage, because this means that you can exclude routes from the RPC by simply not chaining them.
wyrd
wyrdOP4w ago
I see. That makes a lot of sense. Thank you

Did you find this page helpful?