Catching Nested any in typescript-eslint

Published: (December 9, 2025 at 11:12 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

Background

For my open source contribution I decided to keep working in the TypeScript linting space and picked a feature request that asks the no-unsafe-* family of rules to catch any nested inside object arguments, not just at the top level. I read the rule docs for no-unsafe-argument and no-unsafe-assignment to understand how they work today, and why nested any can slip through—for example when you pass { foo: any } to a function that expects { foo: number }. These rules exist to stop unsafe any from leaking into calls and assignments, so closing this gap matters for real apps, not just theory. I also reviewed the project’s guidance on typed‑linting performance to stay mindful of cost.

Implementation

The main change teaches the checker to look inside structures, not only at the top level. It now walks through objects, arrays, tuples, unions, and similar shapes. If it finds a nested any, it reports it, and the rule avoids printing two errors for the same line, so the message stays clear.

  • Added tests to prove the exact repro fails as expected.
  • Fixed a few small spots in the repo that started failing once the checker became stricter (e.g., places that were spreading values typed as any).

To keep the common case fast, I added short‑circuit checks and a guard to skip built‑in library types, preventing noise for users.

Challenges and Learnings

This turned out to be a very challenging issue; I spent many hours untangling type‑recursion logic and dealing with edge cases. It taught me a lot about how typed linting works under the hood. I also learned to:

  • Measure first and keep early exits wherever the source type clearly has no any.
  • Keep error messages focused on the exact unsafe spot, not the whole object.

Reading the typed‑linting overview and performance notes helped me plan these guardrails.

Pull Request

My PR Link

Back to Blog

Related posts

Read more »