How to get union types through Elma ports?

I ran into a problem while testing Elm. I want to pass a union type through a port, but I get this error:

Port 'setStorage' is trying to communicate an unsupported type. 34| port setStorage : Model -> Cmd msg ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The specific unsupported type is: Todo.Importance The types of values that can flow through in and out of Elm include: Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, Tuples, Json.Values, and concrete records. 

I modified the Todo example as follows:

 type alias Task = { description : String , completed : Bool , editing : Bool , id : Int , importance : Importance -- <- this is the new field } type Importance = Normal | High | Low 

This problem seems pretty old. One commenter suggests "passing Json.Values โ€‹โ€‹through the ports and Json.Decode / Encode them", but how exactly can this be done? The documentation looks a bit obscure and does not contain complete examples. Any help is appreciated.

+7
json elm
source share
2 answers

I did work with Json.Decoder / Encoder. In the end, it was not so difficult, although it was necessary to serialize each individual field only in order to convey that one type of union is a rather heavy burden.

decoders:

 modelDecoder : Json.Decoder Model modelDecoder = Json.object4 Model ("tasks" := Json.list taskDecoder) ("field" := Json.string) ("uid" := Json.int) ("visibility" := Json.string) taskDecoder : Json.Decoder Task taskDecoder = Json.object5 Task ("description" := Json.string) ("completed" := Json.bool) ("editing" := Json.bool) ("id" := Json.int) ("importance" := Json.string `andThen` importanceDecoder) importanceDecoder : String -> Json.Decoder Importance importanceDecoder tag = case tag of "Normal" -> Json.succeed Normal "High" -> Json.succeed High "Low" -> Json.succeed Low _ -> Json.fail (tag ++ " is not a recognized tag for Importance") 

And encoders:

 modelToValue : Model -> Json.Encode.Value modelToValue model = Json.Encode.object [ ("tasks", Json.Encode.list (List.map taskToValue model.tasks)), ("field", Json.Encode.string model.field), ("uid", Json.Encode.int model.uid), ("visibility", Json.Encode.string model.visibility) ] taskToValue : Task -> Json.Encode.Value taskToValue task = Json.Encode.object [ ("description", Json.Encode.string task.description), ("completed", Json.Encode.bool task.completed), ("editing", Json.Encode.bool task.editing), ("id", Json.Encode.int task.id), ("importance", importanceToValue task.importance) ] importanceToValue : Importance -> Json.Encode.Value importanceToValue importance = case importance of Normal -> Json.Encode.string "Normal" High -> Json.Encode.string "High" Low -> Json.Encode.string "Low" 
+8
source share

You cannot pass a union type, primarily because JS is not aware of this. So you can pass a string and make a case statement in javascript - I do this all the time.

+3
source share

All Articles