That was definitely the case before ES2015. I think many of the non-JS devs that still hugely wish they could write something other than JS for the browser haven't kept up with ES2015+ nor Typescript. ES2015 is a much improved language and vanilla JS isn't painful anymore, especially with type="module" support now green enough in caniuse statistics that we can finally kill AMD and CommonJS for good in greenfield vanilla JS projects. The sky is quite sunny and ES2015+ is a better language than a lot of non-JS devs think JS is.
It will still be a while before all the brownfields in the larger ecosystem get cleaned up (if some of them ever do), but that's no longer a language problem, that's a a long tail ecosystem problem.
You can use `Map` instead of object which allows keys of any type, or typecheck your objects with `Record<K, V>` and let typescript warn you about any weirdness. Typescript can also warn you if you do some weird implicit coercion. You can typeguard against `null` (although I admit it is annoying, I just want to use an optional†). And if you really want to use integer types there is always `BigInt`.
---
†: I haven’t checked, but I bet there are some libraries out there that provide proper optionals using Proxy.
I use BigInt often, but you can't (for example) do most substring operations with it, even though floating point indexes make no sense.
Map goes part of the way to what I want. But I really want to control which objects are considered equivalent keys, rather than being limited to reference equality.
There's a Stage 2 proposal before TC-39 to add immutable Record and Tuple types [1] which would be structurally compared and perfect for complex Map keys.
It's also easy enough to find or write quick simple Map wrappers that use a hash function on an object as keys when provided (either piggy-backing on the existing Object.prototype.valueOf, which always exists on every object and easily falls back to the reference-based current behavior, and expecting classes to have custom overrides for that, or using a Symbol named function of their own to avoid polluting own-property-keys/name clashes with other libraries).
It will still be a while before all the brownfields in the larger ecosystem get cleaned up (if some of them ever do), but that's no longer a language problem, that's a a long tail ecosystem problem.