【问题标题】:How to pass union types through Elm ports?如何通过 Elm 端口传递联合类型?
【发布时间】:2016-06-23 18:46:30
【问题描述】:

我在试用 Elm 时遇到了一个问题。我想通过端口传递联合类型,但出现此错误:

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.

我已将 Todo example 修改如下:

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

type Importance
  = Normal
  | High
  | Low

这个issue 似乎很老了。一位评论者建议“通过端口传递 Json.Values 并对其进行 Json.Decode/Encode”,但具体该怎么做呢?该文档似乎有点不清楚,并且缺少完整的示例。任何帮助表示赞赏。

【问题讨论】:

    标签: json elm


    【解决方案1】:

    我已经使用 Json.Decoder/Encoder 实现了 work。毕竟不是那么难,尽管为了传递一个联合类型而必须序列化每个字段是一个相当大的负担。

    解码器:

    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")
    

    和编码器:

    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"
    

    【讨论】:

    • 这个功能不会很快实现......在 Elm Slack @rtfeldman 说这个功能在优先级列表中的位置很靠后,如果它在明年发生,他会感到惊讶。截至 2017 年 5 月 23 日。
    【解决方案2】:

    首先你不能传递联合类型,因为 JS 不知道这样的事情。所以你不妨传递一个字符串并在 javascript 中做一个 case 语句——我一直都在做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-04
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多