This is wrong. DotNet uses packages.lock.json explicitly to support the case where you want to be able to lock transitive dependencies that are specified with a range value, or several other edge cases that might warrant explicitly declaring versions that are absent from csproj or sln files.
.NET doesn't have lock files either, and its dependency tree runs great.
Using fixed versions for dependencies is a best practice, in my opinion.