DEV Community

Lets Be Real: Its Time to Ditch `any` for `unknown` in TypeScript

Vatsal Trivedi on September 22, 2025

We’ve all seen it in a pull request. A developer hits a snag with a tricky data type, and to get things working, they reach for the easiest tool av...
Collapse
 
jess profile image
Jess Lee

Great first post!

Collapse
 
trivedivatsal profile image
Vatsal Trivedi

Thank you

Collapse
 
zessu profile image
A Makenzi

any serves to make javascript and typescript interoperable. It's very useful when moving projects from js to ts. do not use it to disable the type system but removing it makes it hard to do smaller migrations or use untyped libraries

Collapse
 
leob profile image
leob

Useful, really learned something today!

Collapse
 
trivedivatsal profile image
Vatsal Trivedi

Thanks!!

Collapse
 
jaro profile image
JaRo • Edited

While reading this I listen to this: https://youtu.be/h9VWxXaep-c?list=RDh9VWxXaep-c&t=714

The future is uknown xD

Nice article btw. Keep it up.

Collapse
 
trivedivatsal profile image
Vatsal Trivedi

Hahaha...
Glad you enjoyed the article!

Collapse
 
kurealnum profile image
Oscar

I have no idea how I didn't realize that this existed... but I'm glad that I do now!

Collapse
 
trivedivatsal profile image
Vatsal Trivedi

Happens to all of us — glad you found it now!

Collapse
 
raziq_din_bd0274cc2ac748b profile image
Raziq Din

Great Read!

Collapse
 
trivedivatsal profile image
Vatsal Trivedi

Thanks

Collapse
 
kylelogue profile image
Kyle Logue

This resonates with me so much! I've been burned by the any escape hatch more times than I care to admit, especially when dealing with API responses in contract-first development.

One pattern I've found particularly useful is combining unknown with type predicates for API data validation:

function isUserResponse(data: unknown): data is User {
  return typeof data === 'object' && 
         data !== null && 
         'id' in data && 
         'email' in data;
}

// Now you get full type safety
if (isUserResponse(apiResponse)) {
  console.log(apiResponse.email); // TypeScript knows this is safe
}
Enter fullscreen mode Exit fullscreen mode

The forcing function aspect you mentioned is spot-on - unknown makes you explicitly handle the uncertainty, which catches so many runtime issues during development rather than in production.

Have you found any particular patterns or libraries that make the type guard approach more ergonomic? Always curious how other devs structure their validation workflows.

Collapse
 
trivedivatsal profile image
Vatsal Trivedi

That’s why I tie linting into the workflow with lint-staged + ESLint. It catches any (thanks to @typescript-eslint/no-explicit-any) before the commit even goes through.

For runtime validation, I usually use JSON schemas when the data gets complex. The pre-commit guard keeps the codebase consistent and pushes us to use unknown with type guards or schemas instead of falling back to the easy escape hatch.

Collapse
 
kylelogue profile image
Kyle Logue

Are you using something like Husky for the pre-commit hook? I use lint-staged as well with a pre-commit hook that runs my package.json eslint . script

Thread Thread
 
trivedivatsal profile image
Vatsal Trivedi

Yes — I’ve set it up with Husky + lint-staged, running both Prettier and ESLint from the package.json scripts in the pre-commit hook. This way, code gets auto-formatted and linted before it’s committed.

Collapse
 
markaurit profile image
MarkAurit

Being "Real" is _not _ introducing something that never should be in a production app in the first place as if it were a good idea. any and unknown should only be used in development situations where the type cannot at that time be known. Any workflow that allows any or unknown into production is flawed. Using unknown because its a better way to trick typescripts' Achilles Heel is not professional.
The article itself is quite well done, bravo.

Collapse
 
trivedivatsal profile image
Vatsal Trivedi

It always comes down to choosing between taking on tech debt or doing the correct solution. Thanks for taking the time to read through!