Unlike the described newtypes approach, formal verification allows you to express arbitrary properties of your data and thus has a significantly broader scope.However, in practice its use is pretty complicated:
You may need to know a special proof assistant language like Coq to verify your programs;
You have to write proofs yourself.
This way, formal verification may often be infeasible for large contracts.On the other hand, newtypes feature lets you put a constraint only on one piece of data at a time, so, for instance, amount > 0 || storage.x > 0 invariant cannot be expressed here; but this feature is naturally embedded in the language and requires a constant amount of boilerplate.