This issue was raised in microsoft/TypeScript#36987. The authoritative (but not particularly informative) answer there is that this behavior is as intended, and required for backward compatibility. Generally speaking TypeScript doesn’t introduce breaking changes unless these changes improve many more things than they break.
When the --noImplicitAny compiler option and the --strictNullChecks compiler option are both enabled, then empty arrays are not really of type any[]; instead they are “auto” or “wildcard” or “evolving” types that change depending on what values are observed to be added to them. This is implemented in microsoft/TypeScript#11432:
let a = []; // auto-typed
a.push(0); // now a is seen as number[]
a.map(x => x.toFixed()) // okay
a.map(x => x.toUpperCase()) // error, numbers don't have a toUpperCase() method
When --noImplicitAny is off, this doesn’t happen, since doing so would have added new errors to existing code which used to be “fine” (if a is of type any[], then x in the map() method should be of type any, and so no error should occur on x.toUpperCase() or typos like x.toFaxed() or anything).
As for the difference between --strictNullChecks being on or off, there were several bug fixes having to do with empty array literals interacting badly with other use cases; see microsoft/TypeScript#19576 and microsoft/TypeScript#19745. These fixes changed the behavior when --strictNullChecks is on, but not when it is off, again to preserve backward compatibility in these other use cases.
So that’s what’s going on, more or less. You’re seeing the consequences of several features and bug fixes interacting in a peculiar way in the face of certain compiler options.
Pragmatically speaking you should always use the full --strict suite of compiler options where possible. This gives you a “standard” amount of type safety and is used widely so there’s a large amount of documentation and discussion in the community. If you selectively disable some compiler options and you run into something strange or unexpected, there are fewer resources available to you, because you might be among very few people with such a configuration. And even if you find a genuine language bug, there will be less pressure for it to be fixed, so it might persist for a long time or forever.
Playground link to code