I used to hate static typing with a passion, and I'm still a pretty big Lisp fan, but I've recently taken up Haskell. Many of the examples in this post use Haskell as an example of the right thing, and I'm really starting to see the advantages. Certain common errors are caught by the compiler, and impure operations show up in a function's type signature, reducing the chances of any spooky action at a distance.
Ultimately, I think there's a tradeoff between flexibility and correctness. How much of each to choose depends on the parameters of the project. Some languages try to allow a choice, especially with regard to typing discipline. Haskell offers Data.Dynamic. Common Lisp has optional type declarations and compiler warnings for obvious type errors. There's a post about formalizing such things as "gradual typing" (http://news.ycombinator.com/item?id=556794).
And most of the time, these decisions are correct. In each language, however, there are usually a few exceptions, most of which are the result of learning over time. For example, Pascal over-uses nominal type equality, which is particularly pernicious with arrays, and, in classical Pascal, strings (fixed-length arrays of chars).
And in Java, requiring most possible exceptions to be part of the interface specification is a flaw resulting from a misunderstanding about exceptions: Java seems to feel that no exception should be ignored, while they should actually almost never be caught.
And then there are abhorrences like C++, where historical forces have combined to give the language user more power than they can comfortably wield, or can be comfortably implemented in any given compiler.