Hono is not type-safe (yet)…

Kevin Firko
Published:

Hono is one of the hottest back-end API frameworks in the TypeScript ecosystem right now.

It bills itself as fast, lightweight, [and] built on Web Standards and it boasts support for any JavaScript runtime. Overall I think that it’s an excellent framework with a bright future.

For some reason nearly everything I’ve read or watched about Hono describes it as “type safe”.

Hono is not type-safe. At least not yet. I’ll explain why in this post.

Versions

This post is relevant to the current release v4.4.12 at the time of writing on 2024-07-10.

The official middleware I mention are also current:

  • @hono/zod-validator v0.2.2
  • @hono/valibot-validator v0.3.0

It’s important to remember that in many respects Hono is still a work in progress that’s advancing per a philosophy to be fast and only depend on Web Standard API’s. Type safety is more of a goal than an achieved milestone.

Consider that the major version number of the @hono packages above is v0.

Why Hono Isn’t Type Safe… (Yet)

Design Decisions

A portion of Hono’s growing popularity can be explained by the familiar experience it offers to developers who have worked with leading predecessors like Express.

I recall when I tried Hono for the first time it felt like I already knew Hono.

While the design decision to feel familiar empowers many it also comes at a cost to the framework: it can be challenging for maintainers to properly type some of the patterns that were popular during the wild-west era of untyped JS.

Similar API’s are possible that are both easier to type among numerous other benefits (for example compare Valibot to Zod) however Hono made its choices and who am I to argue with its popularity.

Escape Hatches

How does Hono provide type safety in the tricky parts?

It cheats.

If you use search the codebase of honojs/hono or honojs/middleware on GitHub you can find plenty of escape hatches like @ts-ignore, @ts-expect-error, and any.

Some escape hatches are understandable and in some cases they’re absolutely necessary. However it appears there are cases where they are used to work around real type issues instead of fixing the core problem and thus they contribute to an illusion of type safety.

Escape hatches should always be employed with extreme caution because they effectively disable type safety and nullify the point of using TypeScript in the first place.

It is for this reason that I always advocate that every escape hatch in a professional TypeScript codebase be documented with an explanatory comment and reviewed by developers who can tell the difference.

If I’m the one coding and I’m not sure about a particular case then I make sure to ask a wizard or two.

A great eslint rule is @typescript-eslint/ban-ts-comment which can be configured with the option allow-with-description.

Escape Hatches in Validation Code

It’s not ideal to find “type cheats” in code whose sole purpose is to provide type-safety and offer assurances about data at run-time.

Let’s inspect the official middleware packages @hono/zod-validator and @hono/valibot-validator.

zod and valibot are popular libraries that offer the potential to deliver type-safety enforced via run-time validation. The corresponding @hono packages integrate them for validating requests.

In both we find the same line in a crucial spot:

// @ts-expect-error not typed well
validator(target, async (value, c) => {
  // ...
})

Doh! The same framework that hype-driven novelty-seeking “tech influencers” are breathlessly calling “type safe” is “not typed well” per its own codebase!

References:

I appreciate the professionalism of the maintainers for explaining the escape hatch in the comment. They’re the ones working on creating something wonderful vs. those playing “influencer” and spreading noise.

If you scroll up from the escape hatch and take a look at the types the maintainers were struggling with you’ll see that they are indeed a doozy.

Type Issues in Practice

I found if one creates a Hono API based on the docs and provided examples i.e. the “happy path” then it is unlikely that any type issues will be evident. The combinations of type definitions + cheats essentially work out in a way anticipated by the maintainers.

This situation changes if you try to create type-safe generic helper functions or utilities related to Hono middleware.

I encountered issues because I like to “flex” any new-to-me framework with relevant experiments before I commit to it for a project. I always aim to go beyond contrived examples like to-do lists where even unmaintainable junk tends to excel.

I found myself hitting inexplicable type issues when I tried adding type-safe generic helper functions and middleware utilities to streamline working with slonik, a respected and truly type-safe library for working with Postgres + zod.

When drilled into Hono’s type exports using VSCode I couldn’t figure out how the types actually worked or fit together.

That led me to inspect Hono’s codebase where I realized it’s because they don’t actually fit together and that’s what led to this post.

Conclusions

Impact of Compromised Type Safety

TypeScript’s type system is only as strong as the weakest link.

Once a type-related “chain of trust” is broken through misuse of an escape hatch then any depdendent types downstream from that point on become suspect.

This means that many parts of Hono’s growing codebase carry the risk of presenting developers with confusing or misleading types.

Examples include the framework’s solutions for supporting OpenAPI/swagger to its much-venerated RPC client feature.

If the root causes are not addressed then it stands to reason that the number of risky escape hatches will only grow. Misuse of escape hatches have a nasty way of proliferating downstream; I sometimes describe them as “infectious”.

Type issues can also sometimes contribute to security issues. For example developers might inadvertently leak secrets because the type system erroneously indicates to them that confidential data fields won’t be present in a response.

Working with the Status Quo

At the end of the day I like Hono and I really appreciate its unique strengths. I am very interested in watching related projects like honox develop.

My hope is that calling out type its issues will attract attention and resources that lead to improvements.

At least for now sticking to the “happy paths” per the docs and examples will just work even if there’s some “magic” at play behind the curtain.

I hope the day comes soon when Hono delivers true type safety through a rigorous “chain of trust” (in the type sense) that spans from end-to-end.