Where to Use ANY in TypeScript
If you follow me, you know I'm extremely against any in code... whenever we want to turn off TypeScript, we can just use any in our code

If you follow me, you know I'm extremely against any in code. Mainly because any has become an escape valve: whenever we want to turn off TypeScript, we can just use any in our code and everything gets solved. Many people have already asked me: “Huh, so why does TypeScript have any if we can't use it?”
The reality is that any is an extremely important type. First, because it's the only type that can be associated with any type without that type being restricted to a more specific type; besides that, it's the most open type of all and accepts everything, in other words, any is everywhere.
While in most cases it's very bad to use any, there are some interesting cases where, in fact, any is our only correct option.
Allowing type inference
The first example is exactly what I mentioned above. When we use any, we're not fixing a specific type and we're allowing TS to infer that type. The way TypeScript resolves typing is always from the most open to the most closed, in other words, any is like initializing a numeric variable as “infinity”.
A classic example of this (which you'll find in many places) is ReturnType, a utility type that exists natively in TypeScript, and basically what it does is get the return type of a function. Let's try to recreate this type:
type ReturnType<T extends (...args: unknown[]) => unknown> = T extends (...args: unknown[]) => infer Retorno ? Retorno : neverBasically, we're saying we want a type, this type takes a generic that will be a function, and we really don't care what exists in the parameters or the return of the function, so instead of having to use any we'll use unknown. This way our type becomes safer, right? But what if we do this here:
const foo = (i: string) => i
type retorno = ReturnType<typeof foo>ype '(i: string) => string' does not satisfy the constraint '(...args: unknown[]) => unknown'.
Types of parameters 'i' and 'args' are incompatible.
Type 'unknown' is not assignable to type 'string'.This is because when we use unknown we're automatically telling TypeScript that we don't know what's there, so TS will force us to cast it manually, and what we want is for TS to do the inference on its own. So for that we have to say that “we don't care what's there” and TS will always try to bring the most specific type possible.
If we change our type declaration to:
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer Retorno ? Retorno : neverOur error disappears and our retorno type will be string.
External values
Another option is when we're dealing with values that are truly external. This is a valid case for using any, but we always have to remember that we need to type these types afterwards. For example:
const dadoExterno: any = algumaChamadaDeAPI()
// processing here
const dadoInterno: SeuTipo = dadoConfirmadoany in this case is only when we're obtaining the data, through a JSON.parse or any other call, but it's extremely important that we don't keep the any afterwards; if we need to do any processing, it's important that we cast that type to another, much more specific type.
Codebase migration
One of the most important use cases is when we're migrating from JavaScript to TypeScript in an old codebase. For this, it's common that we start the migration using any in the old code and, little by little, move those any to specific types.
This is probably the most acceptable case for using any in any application.
Translated from the Brazilian Portuguese original · Read the original





