Soft typing could be characterised by having the compiler do static type analysis where it can, but leave the type analysis to the runtime when it can't.
A simple example of this is a list. Now in statically typed languages, list are homogeneous (this is includes type unions). In dynamically typed languages, list can be heterogeneous, essentially anything can be added at runtime.
In soft typing, we can indicate that a list is homogeneous and the compiler will ensure that this is true or we can specify no type checking (as such) and this will be done at runtime.
Contrived yes, but I regularly use other aggregates (tables and sets) into which I do not want them to homogeneous.
One of the aspects that I like about functional languages is the polymorphism available, but in all that I have come across, there is no way to make a tree or list heterogeneous without declaring union types before hand.
My problem with C#, C++, Java, and their ilk, is that code is multiplied with their generics.
How the IDE and compiler and type systems interact is a design function and is not inherent to any type system.
One of the reasons I don't use specific main stream languages such as C#, C++ or JAVA is that they don't provide the specific programming features that I desire.
I have looked at Go, Swift and Rust and I am not at all impressed by the "relative stupidities" within those languages. For other programmers, what they consider to "relative stupidities" is entirely up to their experience and outlook.