-
|
This is a genuine question, not a critique. Hono has been a delight to use and has already saved me days of work - but still curious; By default await Hono is a relatively recent framework. The focus on web-standards and being a micro-framework seems to align (intentionally or unintentionally) with the general JS ecosystem shift away from vulnerable, magical and bloated dependencies to more secure, explicit and thin dependencies. Alongside the security focused shift in libraries there is a parallel shift in TypeScript towards more and more strictly typed projects. The theories of "Type Driven Design", "parse, don't validate" and "boundary validation" have been around for a while. The I understand the function can take a generic ( Hono looks to be poised to be the framework of choice for modern TS projects wanting to move away from the supply-chain-attack mess currently unfolding, but this seems like a bit of a miss in relation to type safety so I wonder what I am missing or what the logic was for returning I know that code review, custom lint rules etc etc could work-around this, but that is still a workaround - educating junior developers is difficult enough without the argument of "if unknown is more accurate than any then why would a modern framework return any?" I did stumble across this thread, but again, its a workaround and I don't see reasoning; |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 1 reply
-
|
The short answer is: Hono deliberately mirrors the Web Platform's own Why the Web Platform returns
|
Beta Was this translation helpful? Give feedback.
-
|
Short version: the Why json<T = any>(): Promise<T>So the default isn't "we chose You can get exactly the boundary you want — right now. Because it's const body = await c.req.json<unknown>(); // Promise<unknown>
// now you're forced to validate/narrow before use — "parse, don't validate"If you want this project-wide (so juniors can't accidentally get const readJson = (c: Context) => c.req.json<unknown>();
// or a tiny middleware/helper your codebase uses everywhereYou can also enforce it at the lint layer with And the first-class answer to "parse, don't validate" is the validator, which is genuinely parse-and-narrow (not an assertion like import { zValidator } from '@hono/zod-validator';
app.post('/', zValidator('json', schema), (c) => {
const data = c.req.valid('json'); // fully typed AND runtime-checked
});So the design intent is: default = platform-faithful and non-breaking ( |
Beta Was this translation helpful? Give feedback.
-
|
I would prefer to hear from a maintainer rather than what appears to be curated LLM responses. @usualoma @yusukebe apologies for directly pinging, but if either of you find time to give even a brief response it would be appreciated |
Beta Was this translation helpful? Give feedback.
-
|
Hi @darcyrush Thank you for the thread, and sorry to be late. The reason is simple: as you said, I can understand the merit of returning Plus, actually, there was a policy for me before I created Hono that made it easy about types. This isn't told, but I wasn't super familiar with TypeScript when I started creating Hono. My thought about TypeScript types was that they can be "loose": the value could be But anyway, we have to accept modern things. |
Beta Was this translation helpful? Give feedback.
Hi @darcyrush
Thank you for the thread, and sorry to be late. The reason is simple: as you said,
JSON.parse()returnsany, so I followed it. As you said, users can usec.req.json<MyDto>()to specify the type andc.req.valid()for validation.I can understand the merit of returning
unknown, and we have to consider it for the next major release.Plus, actually, there was a policy for me before I created Hono that made it easy about types. This isn't told, but I wasn't super familiar with TypeScript when I started creating Hono. My thought about TypeScript types was that they can be "loose": the value could be
any, and this was no problem. It's a historical reason.But anyway, we have to acc…