RPC types not working well inside a monorepo
I have a monorepo setup with
packages/api
for my hono api and app/www
for the client code. I have set up rpc well but i am getting Type instantiation is excessively deep and possibly infinite.ts
. I have tried the following
- I have set strict
to true on both my api and client package
- have set composite
true in my api package and set path reference in my client package.
The above two helped to infer the types in the client from unknown to actual types but now its giving the type instantiation error.
Also my routes are chained and splitted accordingly like this
now getting the type error here
63 Replies
For typescript to be aware of the routes everything must be chained together in one expression.
e.g.
This is smth the docs fail to mention, and the given example in the docs should not have worked
I don't know what sorcery the docs did
Also, don't import
app
directly in your frontend
If your project so far doesn't have proprietary code, can you share the code?
When I am free I can help structure typescript stuff better, unless you wanna try on your ownwhich example do you mean?
For hono client,
hc
, in the hono stacks guidedamn. no bueno
i've been meaning to open a PR to make some docs updates. i can add this to those, unless you'd like to open one for this @Arjix
Feel free to do the update, unfortunately I lack the free time and energy to do it myself
fair enough. i've got nothing but time, lol
I guess the docs are correct in the code example, but they are pretty ambiguous I'd say
There is an inconsistency in the code style used
@Tony on an unrelated note, it's helpful if you add syntax highlighting to your code snippets. discord supports markdown syntax, so you can just add the language after the opening backticks, e.g., ```typescript
but i kinda do this already
no, you're right. i tried it out on my local and the client can't infer
Typescript can't infer that they are all linked together
^
shoot, let me give it a try and update u
Yeah the docs rewrite the backend w/o explaining why, so the example is correct but it doesn't tell you to write your code like that
It simply tells you to export it's type
ahhh. you mean
yeah. that's sneaky
Yep
Very ambiguous
Totally needs clarification
Update where
I have tried on my own but havent managed to get it working. the ts inference and autocomplete are slow af. when u get a min u can check it out maybe
https://github.com/BrightonMboya/jani-payments
GitHub
GitHub - BrightonMboya/jani-payments: A Billing Engine where you ge...
A Billing Engine where you get to bring your own Payment Provider. Think of it as Stripe | Paddle | Polar.sh but with Mobile Money support out of the box - BrightonMboya/jani-payments
you may need to chain here too: https://github.com/BrightonMboya/jani-payments/blob/a31f1b1c68ef3fb37512f838ab65673c40af055e/packages/api/src/lib/create-app.ts#L19
and you probably want to be using generated types for the client
nmkl\
so chaining it on 2 places?
how do you do that?
typescript only knows what to do with the initialized type of a value.
if you split up your method calls, it has no way of knowing you've done that
you could do this
but the final type of
export app
is going to be the type at initialization
does that make sense? it's not a hono thing, just how typescript worksnot really mate, I am getting confused
i am kinda doing that here no? https://github.com/BrightonMboya/jani-payments/blob/a31f1b1c68ef3fb37512f838ab65673c40af055e/packages/api/src/index.ts#L14C1-L22C21
or maybe i am confused with the way i have set things up already
idk, tbh. you have this in your
tsconfig
already, but you might have to also configure the bundler? i'm not sure, sorry
you are there, but not here:
https://github.com/BrightonMboya/jani-payments/blob/a31f1b1c68ef3fb37512f838ab65673c40af055e/packages/api/src/lib/create-app.ts#L19
you break the chain at the startyes i have this in my tsconfig, what i am not sure is a way of generating the types,
me neither. sorry
the short answer RE your typing issue is that you're doing a lot of abstraction for a Hono app. if that's your preference, that's totally fine, but it makes it harder for typescript, and that will cost you performance
generated types will help some though
i think these docs might be helpful: https://hono.dev/docs/guides/best-practices
@Tony this might also be helpful: https://hono.dev/docs/guides/rpc#compile-your-code-before-using-it-recommended
@Tony typescript types are immutable, that is the fundamental issue here
Every time you alter the type (by adding a route) you are creating a new type derived from the previous type
Therefore, if you assign routes to your app using a loop, you are not altering the original type of the app
Inside the loop you are creating a new temporary type derived from the blank app + the current iteration of the routes
In my template I show how to get rpc working
https://github.com/ArjixWasTaken/vite-react-ts-hono/tree/main/src/backend
GitHub
vite-react-ts-hono/src/backend at main · ArjixWasTaken/vite-react-t...
A template based on vite+react+ts with hono as an addition. - ArjixWasTaken/vite-react-ts-hono
Basically, you need to chain all the routes together in one statement
It doesn't mean you can't split your routes into folders, it just means you can't use convenience methods like a loop to dynamically register them
great explanation!
Thanks, it took me a while to ponder it
I get this part of chaining the routes. I did that and the initial error of
type instansiation is deep and possibly infinte
the new issue comes with the rpc inside the client is very slow on type inference and auto complete. it gets the type yes but its slow
I am trying the fix of using generated types suggested by ambergristle
maybe i am missing sth very obvious which i cant see it yetPls ping me tomorrow, I share what I've came up with
Nutshell, monorepo with workspaces, hono app package json has types property which points to client.d.ts
alright cool !!
thanks a ton
/package.json
"workspaces": [
"backend",
"web-ui"
],
/backend/package.json
"type": "module",
"main": "dist/src/client.js",
"typings": "dist/src/client.d.ts",
/backend/tsconfig.json
composite true
/ui/package.json
"backend": "workspace:*",
/ui/tsconfig.json
"references": [
{
"path": "../backend"
}
So in ui package.json we reference the NAME of backend module (name prop of /backend/package.json) which helps ide and bundler to pick up the generated type
The typescript project references is only for (re)build if you change backend stuff without explicitly build it
In vite config We must use
checker({
typescript: {
buildMode: true,
},
Sry for missing backticks, I'm on the phone right now
damn it, somehow i keep on getting confused on this. do u mind checking it out on the repo ? or maybe sending u a minimum repo will work for you?
basically the main issue rn is the rpc type inference and autocomplete is not fast in the client, basically in this file here
https://github.com/BrightonMboya/jani-payments/blob/a31f1b1c68ef3fb37512f838ab65673c40af055e/apps/www/src/server/hono.ts#L6
it gets the types yes, but the automplete part is the one which is super slow
Yes it's because you don't compile your types. I will get to it later
I guess thats the culprit, have tried running this through claude but no luck
@Psi is this what you mean RE compiling types? https://hono.dev/docs/guides/rpc#compile-your-code-before-using-it-recommended
There is trpc stuff in your repo?
And I dont see type path definitions in your package.json
there was a trpc api on the
apps/www
package but i slowly migrated it to hono. so u can just ignore the trpc stuff
yeah this is what i havent done yet, still confuses me to get the compilation correct
I tried this, but it could still be slow on the type inference and auto completeautocomplete in "backend/client.ts" is ALWAYS slow. so it is for the backend in general BUT not in frontend
so there's no workaround for this?
GitHub
GitHub - psi-4ward/hono-rpc-vite-example
Contribute to psi-4ward/hono-rpc-vite-example development by creating an account on GitHub.
You do usually not need your own client in the backend dont u? 😄
yeah the client is meant for the nextjs app
Than test your autocomplete here!!
which i am already, are we on the same page though
there's definitely some miscommunication happening
the repo you've shared has a lot going on, including a monorepo manager i haven't seen before, so it's really difficult to isolate the problem
also, IDE performance can depend a lot on other factors, including the IDE itself and your device specs
there are known issues with Hono + IDE Performance at scale. these are somewhat documented, but there are also threads on this server that have more details
sharing a minimal example would be helpful, along with any instructions required to reproduce what you're experiencing
Thy can be completly solved be pre-compiling the type and consume ".d.ts" file afaik
depends on how many endpoints you have, and how complicated your typing is
at 50-100 endpoints, hono is known to struggle
I let AI generate 1000 endpoints each with get/post/put/delete.
No problems so far cause it results in (a very large) client.d.ts BUT thy only magic here is the ClientRequest type which is not so hard complicated.
tbh, first I liked the way hono handles the types but meantime I changed my mind.
defining them explicitly whould make thing much more easy and clear
i can't comment on what the AI generated. i just know that there are a number of open issues RE performance, and that there's some clear albeit limited benchmarkiing
you can set the types explicitly if you want. or is that not what you mean?
Afaik can I not set the type on route handler to circumvent the hono magic
Imo it’s not ideal, but yeah. If that’s what you prefer, or if you’re having serious performance issues, it’s an option
Can you throw a link around or a little example?
Afair had @Aditya Mathur a good article about that but did not bookmark it and could not find it anymore ðŸ˜
I dont understand this. This means
'foo/:id'
generic makes things faster?Typescript can run DOOM, yet it struggles computing all the routes?
(I obviously know that it takes a long time to generate a single frame)
Yeah. You might want to also specify the inputs + outputs using the rest of the generic parameters, but even specifying the path reduces how much inference the server needs to do
Hono merges all the route types together, and then exposes them individually in a handler or the rpc. That’s a lot of inference
There are clearly some issues with this at scale, and imo it requires some funky patterns (e.g., manually typing middleware, but not handlers)
You can ignore me, I was partly joking, but it is darn impressive that it can run DOOM
Lmfao. That is pretty insane
Is that like a law of computing? Given enough time, someone will try to run DOOM in every execution context
DOOM + bad apple
https://canitrundoom.org/ 😄🥸🤓
Can It Run Doom? An Archive of All Known Ports
Explore an archive of Doom ports showcasing how the game has been adapted to run on various devices, even those not originally intended for gaming.
Now I also wanna know which one was it? 😂