All of us who have been developing in Elm for any amount of time has dealt with this.
Without rehashing what has been said, I’d just add that, philosophically, this is the price you pay for perfection.
That may sound grandiose, but what I mean by that is that, with Elm, you can only write production code. There is no such things as “hacking” in Elm.
If it compiles, you can ship it.
The downside is that this is part of the price you pay. You have to be specific. That’s why nothing ever breaks.
Also, I disagree with your statement about Dicts. We use LOTS of forms (multi-page) and ended up going with Dicts, but using Dicts of union types. Type-safe AND no boilerplate!
e.g. in the model:
type alias Model =
{ formFields : Dict String AnswerValue }
and the type:
type AnswerValue
= AnswerValueNone
| AnswerValueString String
| AnswerValueBool Bool
| AnswerValueCsv String
| AnswerValueFloat Float
| AnswerValueInt Int
| AnswerValueRangeInt ( String, Int, String, Int )
then a single update function, something like:
UpdateFormAnswerValue key answerValue ->
let
updatedFields =
Dict.insert key answerValue model.formFields
in
( { model | formFields = updatedFields }, Cmd.none )
(This all rather simplified from what we actually do, as we also push data out a WebSocket as we update, we support multiple forms, etc. But hopefully, you get the gist!)
We use a dot notation to name fields. e.g. user.contact.email, user.contact.address, etc.
We have a separate semi-complex form validation library that validates things like email, phone, currency, values based on values in other fields, required fields, max/min values, etc.
Works brilliantly.
(Someday I’ll write it all up, or open source it…)
Anyway, best of luck, I HIGHLY recommend sticking with Elm!!!