Search code examples
jsonelmdecoder

How to decode tagged union types in Elm?


If I have a certain tagged union type, like Shape here, how would I construct a JSON decoder for it in Elm?

type alias Rectangle = { width : Int, height : Int }

type alias Circle = { radius: Int }

type Shape 
    = ShapeRectangle Rectangle 
    | ShapeCircle Circle

Solution

  • Given your JSON looks like

    { "radius" : 10 }

    or

    { "width" : 20, "height" : 15}

    Then this will do the trick

    import Json.Decode as Json exposing ((:=))
    
    decodeShape : Json.Decoder Shape
    decodeShape =
      Json.oneOf
        [ decodeShapeRectangle
        , decodeShapeCircle
        ]
    
    decodeShapeRectangle : Json.Decoder Shape
    decodeShapeRectangle =
      Json.map ShapeRectangle <|
        Json.object2 Rectangle
           ("width" := Json.int)
           ("height" := Json.int)
    
    
    decodeShapeCircle : Json.Decoder Shape
    decodeShapeCircle =
        Json.object1 (ShapeCircle << Circle)
             ("radius" := Json.int)
    

    A couple of additional things: I often add a 'type' and 'tag' field to help disambiguate when I have data types with common field names. The JSON then looks like

    { "type":"shape", "tag":"circle", "radius":10 }

    Also, I think := will be replaced by field in the upcoming 0.18 release.

    Regards,

    Michael