There is no best way. Fortunately the Elixir core libraries are annotated with typespecs, which gets you like 30% there. But dialyzer sucks, and the typespec syntax itself, as well as its expressiveness, leave a lot to be desired. It's clearly an afterthought.
One day I'm gonna make a TypeScript for Elixir.
Note: There's eg Gleam a statically typed language for BEAM, but it's quite unlike Elixir and it has a much smaller community. https://github.com/gleam-lang/gleam. I doubt using eg Phoenix on Gleam is possible, or if it is, whether it's fun. It looks promising though, especially if you're into Ocaml/Haskell-style "hard" FP.