You can check with Clojure and ClojureScript to target JS specifically. You can write your backend in Clojure and the front part in ClojureScript. Having the possibility to use the same language for both is great.
It's a mature functional language with interesting properties, it's practical, data oriented. Libraries quality are top notch, you'll find no big framework but libraries working together to achieve what you want.
Some ClojureScript libraries are awesome, for example if you're on React you have Reagent or Rum that are fantastic libraries to work with React.
OP post could be written like this in Clojure (if you want to be explicit with all the screens):
(defn needs-cancel-button [screen]
(case screen
:screens/loading true
:screens/code-entry true
:screens/success false))
You'll notice that this is not typed but you can use Clojure spec to have some validation (this way being less explicit just returning false for the Success Screen, and true otherwise):
(def screens #{:screens/loading :screens/code-entry :screens/success})
(defn needs-cancel-button
[screen]
{:pre [(s/valid? screens screen)]}
(case screen
:screens/success false
true))
Union types can be mimicked using spec, you'll find how here:
https://lambdaisland.com/blog/25-09-2016-union-typesOCaml is also great, IMO you won't lose your time by learning these languages, you'll find some way to improve your current code
Whether you learn Clojure, OCaml, F#, Haskell, Elm or Haskell, you'll end up being a better developer.