Any Again. Note for a Newbie

The reason for this note was several circumstances. Negative experience on one project, and the following speech in one of the reports on the 2023 TS:
“So when should you use any? Never. I'm joking, of course. If you're porting or developing generics, you can” – I can't answer for the exactness, but the gist is something like this.
And also statements from some teams in the spirit of: “We have a great project. We don't have any”

So how should an inexperienced developer treat any?

Documentation

First of all, let's turn to the modern documentation for the vehicle. And we have next:

TypeScript also has a special type, any, that you can use whenever you don't want a particular value to cause typechecking errors.

And this can really be misleading, that with any can be treated like any other type and used in development.
Because it sounds like: “We have a type here to hide typing error messages”

Example 1.

export const anyAgainEx1 = () => {
  const A: any = 1
  const B: string = A

  const C = B.repeat(10)
}

By running the test we will get confirmation that the function will throw an exception with an error B.repeat is not a function

So, use any as a type in the TS project it is impossible, because its main function is to disable typing at the point of use.

And the documentation says this in plain text. But not in the section dedicated to it. anyand in what I consider to be a very distant section, Do's and Don'ts:

Don't use any as a type unless you are in the process of migrating a JavaScript project to TypeScript. The compiler effectively treats any as “please turn off type checking for this thing”. It is similar to putting an @ts-ignore comment around every usage of the variable. This can be very helpful when you are first migrating a JavaScript project to TypeScript as you can set the type for stuff you haven't migrated yet as any, but in a full TypeScript project you are disabling type checking for any parts of your program that use it.

And if we don't know what type should be in place we should use unknown

Example 2.

export const anyAgainEx2 = () => {
  const A: unknown = 1
  const B: string = typeof A === 'string' ? A : '1'

  return B.repeat(2)
}

Generic

When we have a TS project any you can still use it in it.

Example 3.

type A<T> = { value: T }
type B<T> = T extends any ? A<T> : never
type C<T extends { value: any }> = T extends { value: infer InnerT } ? InnerT : never

type testType = string | number

type Result = {
value1: A<testType> // { value: string | number }
value2: B<testType> // { value: string } | { value: number }
value3: C<A<string> | B<number>> // string | number
}

We have two examples of expressive use any

  • In the first case, the TS thus allows the inclusion of the distributivity of the union when transferring to a generic

  • In the second case, with the help of any we have defined a constraint form for the generic type

Disabling typing via any as a working option

Task: Write a decorator for a function that counts the number of calls

Example 4.

export const anyAgainCounts: { [key: string]: number } = {}

const decoratorCount = function<T extends (...p: any) => any>(fn: T, desc: string): T {
  anyAgainCounts[desc] = 0

  return ((...params: any[]) => {
    anyAgainCounts[desc]++

    return fn(...params)
  }) as T
}

Key points to use any:

  1. Specifying a form for a parameter type decorated by a counting function

  2. Disabling typing, because in this case we are not at all interested in what parameters the decorating function works with. The decorated function should take care of the number of parameters.

Without any the example looks like this:

const decoratorCount2 = <F extends (...args: Parameters<F>) => ReturnType<F>>(fn: F, desc: string) => {
  anyAgainCounts[desc] = 0

  return ((...params: Parameters<F>) => {
    anyAgainCounts[desc]++

    return fn(...params)
  })
}

The key point is that the type system design has become more complex, but we don't use any of it in the implementation itself.

Conclusion

So what does the phrase mean: “We don't have any on our project”?

Firstly, it speaks about the stage of the project. Either it was originally on TS, or all porting operations are completed.

Secondly, any can still be used effectively in a TC project, but as a type its use is limited to clear, well-thought-out situations. If the project really doesn't like any just like that, then it definitely makes sense to familiarize yourself with the features from this note.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *