Just use Erlang with Dialyzer. It's not quite as nice as a lanugage with types built-in, but if you're strict about using it, it does work. I won't code without it.
I have burned more time than I care to admit trying to decipher dialyzer output shenanigans. I love dialyzer when my code doesn't generate any errors, and the rest of the time I kind of want to cry.
Not sufficient, and not for Erlang, but Dialyxir has a `mix dialyzer.explain` command, which gives an example of code that might cause a certain error. Some errors I have been unable to reproduce and I welcome examples of code that would produce them, so PRs are welcome =). Here is what I say for no_return, for example [0].
I maintain a library for converting Erlang Dialyzer messages to Elixir (Erlex [1]) which I hope to one day be able to retire with a stronger Elixir/Erlang communication (AST instead of string communication, e.g., and direct diffs between types).