Tarmil / FSharp.SystemTextJson

System.Text.Json extensions for F# types
MIT License
329 stars 45 forks source link

Add Support for Untagged Unwrapped Single Cases #135

Open daniellittledev opened 1 year ago

daniellittledev commented 1 year ago

To be able to serialise into a typical (untagged) typescript union I propose adding support for a JsonUnionEncoding.Untagged ||| JsonUnionEncoding.UnwrapSingleFieldCases combination that support untagged and unwrapped cases.

Types such as the one below are quite common, and adding a tag is unnecessary and unwanted in this case.

type Value = number | number[]

The equivalent type in FSharp would be as follows.

type Value = Choice<decimal, decimal list> 

If we support primitive types with the constraint of one unique type per case we can also support deserializing without ambiguity.

Looking at the type type ChoiceOf5 = Choice<int, string, bool, int list, Object> we can deserialize the type knowing only the JsonTokenType. So the following type can be round trip-able without any tags.

Choice1Of5 1 = "1"
Choice2Of5 "F#" = "\"F#\""
Choice3Of5 false = "false"
Choice4Of5 [1,2] = "[1,2]"
Choice5Of5 { name = "Object" } = "{name:\"Object\"}"

Duplicate types could fail or attempt to pick the first matching type.

ssiltanen commented 10 months ago

Is there any reason this feature is not acknowledged or does it just need help to implement? I see there already is an old PR for this also that has been ignored. Is there some issue with the approach it is taking?

Although, since there is already a feature to unwrap untagged object, I think this feature should only target single non-object single values (Not sure how arrays behave with the other existing options).

E.g. a use case from the language server protocol definitions:

type A = Enabled of bool | Options of Object
type B = { a: A }
let b = { a: Enabled true }

b should be allowed to be serialized to

{ "a": true }