How to not break type inference with middleware?
Hey eveyone, when doing something like this:
The Hono RPC client breaks for the POST / route.
Property '$post' does not exist on type '{ ":orgId": { "*": ClientRequest<{ $post: { input: { json: { name: string; }; }; output: { organizationId: string; }; outputFormat: "json"; status: 200; } | { input: { json: { name: string; }; }; output: { organizationId: string; }; outputFormat: "json"; status: 201; }; }>; }; } & ... 9 more ... & { ...;How to fix this?
17 Replies
it's probably
client.index.$post, no?I don't have that option, just :orgId

interesting. so you don't have
api.orgs.index.$post?
your code looks fine, so i'm not sure what the issue is
i can't repro an issue with your snippet locally. it could have something to do with the create org logic, but that seems like a stretch
i'd recommend trying to get a simple reproducible example working (or not)No, and if I comment the
.use block I get api.orgs.$post, not api.orgs.index.$post
Can you try this?
if you do api.test. the auto-complete should only type :testIdhm. i see. that's kind of strange
there are a few short-term fixes
- use a sub-route for
/:testId
- move the /:testId middleware to the top of the chain
- leave the /:testId middleware where it is, but remove the path. i'm pretty sure that middleware doesn't get applied to routes it's chained after. you'd need to double-check though
i'll take a closer look at the typing when i have a sec. it's probably just an artifact of hono's type system, but it's a little strange that middleware is totally breaking the chain
@Franco Romano Losada one call-out though: you should never return next from hono middleware
just await it
it should be fine from a technical perspective, but there's no real advantage, and it introduces unneded complexity to the request flow, which can make debugging harderI feel quite stupid because I tried so many ways but not to move the middleware to the top of the chain. Thanks a lot
Removing the path was one of the solutions BUT then
c.req.param('orgId') doesn't work because it needs the path. I wish hono exposes the internal function in the hono/route package.no problem! we've all been there, lol
Noted!
i'm not sure i follow this.
or do you need the path param in the middleware itself?
Yes, exactly, I need the path param in the middleware
ngl, this typing thing is pretty strange. i'll need to take a closer look when i have a bit more time
can I help you? can you point where the type generation is happening in hono source code?
you're welcome to poke around. i'll let you know if i come up with any hypotheses
this is the core typing: https://github.com/honojs/hono/blob/fa8eef707990e80a593fa32c2f67713a2ecd2e9b/src/types.ts#L73
but this may also be relevant: https://github.com/honojs/hono/blob/main/src/client/types.ts
right now i'm thinking it has to do with how hono merges types together, which i think happens in the client typing, but it's been a while
so i'd probably start by creating a pretty simple set of routes, and just mess around with the typing to see what different levers do, and how middleware affects typing
and maybe copy/paste some of hono's types into my own project, to see if i can recreate the same type logic manually
@Franco Romano Losada so i finally had a chance to look into this
turns out its explicit/intentional behavior: https://github.com/honojs/hono/blob/971106d132ec8a989be12ec5c8e63cfaf597cd4f/src/hono-base.ts#L152
using to take a step back, the typing is correct, in that it's consistent with the actual
sorry, i got a little confused. that doesn't actually explain this issue
i've narrowed it down to this though
ok. so this is a bug, but it's an unintendent consequence of a different bug fix
here's the case it's supporting:
calling methods with a
app.use('/path', middleware) updates the Hono path
use method behaviorpath argument sets the Hono internal _path property, which is then used if the immediate downstream method doesn't have a path (otherwise it defaults to basePath, i guess)
anyways, hono's type system does some type merging behind the scenes to resolve things correctly, and this breaks down when you start to venture into these sorts of edge cases
the way that the internal _path gets typed on the instance is also involved
idk. i'll open an issue with my findings so someone with more ts experience (or knowledge of the system) can take a crack at itGitHub
Downstream methods without
path args break upstream method path t...What version of Hono are you using? 4.10.5 What runtime/platform is your app running on? (with version if possible) Bun 1.2.13 What steps can reproduce the bug? a typing edge case was reported on d...
Hi mate, I'm really sorry I dissapeared and couldn't help you debug this. I had some of the stressful days of the last years
Thanks a lot for debugging it and creating the issue
no worries! i just wanted to satisfy my curiosity. hope you're feeling better!
Thank you 🙂