And that kind of works in a dynamic language. You could make it work in a statically-typed language, but then the problems will become more apparent. If X depends on Y and Z1 and Y depends on Z2, and Y exposes an object created by Z2 in its public API, the X developers might look at the Y api docs and try to call Z1 functions on that Z2 object! Worst of all, it might very well work in the normal cases, and the issue might not be noticed until it's in production.
Using multiple versions of the same library is code smell. It's a stability issue, a security issue, a complexity-breeder, and an absolute nightmare for packagers.
And npm allows it to happen silently.