Open Bananas-Are-Yellow opened 4 weeks ago
Each time I come across this problem, I have to add the
[<JsonFSharpConverter>]
to my record and then add[<JsonName>]
to each field to achieve camelCase in JS to be consistent with howSystem.Text.Json
works.
You might think this is not a big deal, but there are times when I want to return a few values from JS as an ad-hock object to be received in F# as an anonymous type. This is a very convenient way to work.
My JS function would return:
return { name: getName(), age: getAge() };
And then my F# function would do this:
let (result: {| Name: string; Age: int |}) = js.InvokeAsync ("MyFunction", ...)
let name = result.Name
...
This works fine, but there are times when I want to handle error conditions, so I have my own version of Result
for use with JS Interop:
[<Struct; JsonFSharpConverter(...)>]
type Result<'t, 'error> =
| Ok of result: 't
| Error of error: 'error
The union is handled by FSharp.SystemTextJson
but this means the result type is now also handled by FSharp.SystemTextJson
. So now I have to either break the JS convention and use object fields in PascalCase:
return { Name: getName(), Age: getAge() };
Or I have to stop using the F# anonymous type and declare an actual type with the [<JsonFSharpConverter>]
attribute and [<JsonName>]
on each field, just because I'm using the Result
union.
I have a Bolero application and I send F# unions to JavaScript and back using
IJSRuntime.InvokeAsync
.JSRuntime
usesSystem.Text.Json
and hasJsonSerializerOptions
with:This means F# record fields are converted to camelCase when serializing to JS, and a case-insensitive match is used when deserializing back to an F# record. I like this behavior because it is conventional to have JS object fields in camelCase and F# record fields in PascalCase.
JsonSerializerOptions
is an internal property ofJSRuntime
, so I can't change this behavior in any case. The code is here. Since I have no control over theJsonSerializerOptions
, I have to use attributes to control the behavior ofFSharp.SystemTextJson
.I am using
FSharp.SystemTextJson
for F# unions, so my union types have the[<JsonFSharpConverter>]
attribute applied. Some of my unions contain record types, and it seems that these also get handled byFSharp.SystemTextJson
even if they do not have the[<JsonFSharpConverter>]
attribute.This is a constant headache for me, because the default behavior of
FSharp.SystemTextJson
for records is to preserve the case of record field names. It means a type without the[<JsonFSharpConverter>]
attribute behaves differently depending on whether it is serialized directly (which usesSystem.Text.Json
) or serialized as an embedded type in a type that does have the[<JsonFSharpConverter>]
attribute applied.Each time I come across this problem, I have to add the
[<JsonFSharpConverter>]
to my record and then add[<JsonName>]
to each field to achieve camelCase in JS to be consistent with howSystem.Text.Json
works.It would all be so much simpler if types with
[<JsonFSharpConverter>]
are handled byFSharp.SystemTextJson
, and types without the attribute are handled bySystem.Text.Json
. Is there a reason why this is not the case?