Inference reads what you handed it, and where there is nothing it writes any
The common read: TypeScript works out a type from how a value is used, so leaving the annotation off costs nothing and the checker fills in whatever I meant.
Inference does not search for what you meant. A variable's type comes from its initializer, an array's element type comes from a best common type chosen out of the candidates actually present, and where those candidates share a base class that nothing in the array actually is, the handbook's own worked example says the compiler makes no inference about the element type and hands back the union instead.
Nothing flows backwards from a later line. Where there is no value to read at all the answer is not an error and not a guess, it is any.
What turns that fallback from silence into a diagnostic is a flag rather than a language rule, noImplicitAny, which you get for free in 7.0.2 because strict defaults on, and it fires where the compiler can see that IT gave up (TS7006 on an unannotated parameter, TS7008 on a member of an object type with no type of its own) and it has nothing to say about an any that arrived from a library signature or from your own keyboard.
That gap is why a review comment reads "this file is fully typed, strict is on, we are covered", on a configure(opts: { retries: number, onError }) that accepts literally anything in its second field, filed as a callback bug in the consumer three sprints later when someone passes an object. Annotate the boundaries and let inference have everything else; the annotation is not documentation of what the value is, it is the only way to say something the values in front of the compiler do not already say.
