jsontype is a small Go module that preserves Go types when marshaling values
to JSON. It embeds type information directly into the JSON alongside the value.
This is useful in scenarios where you marshal and unmarshal JSON to composite
types, such as map[string]any. It ensures that Go types are preserved during
a round-trip.
Install using go get:
go get github.com/ctx42/jsontypeCreate a Value instance encapsulating the value and its type.
jType := jsontype.New(uint(42))
data, _ := json.Marshal(jType)
fmt.Println(string(data))
// Output:
// {"type":"uint","value":42}Later when unmarshalling the library is looking at the type field, finds the
matching converter in the package-level registry and converts the value.
data := []byte(`{"type": "uint", "value": 42}`)
gType := &jsontype.Value{}
_ = json.Unmarshal(data, gType)
fmt.Printf("%[1]v (%[1]T)\n", gType.GoValue())
// Output:
// 42 (uint)The package-level registry provides converters for the following types:
intint8int16int32int64uintuint8uint16uint32uint64float32float64byterunestringbooltime.Durationtime.Timenil
You may register a custom converter for your custom type.
// Custom converter for a type named "seconds" representing duration in seconds.
cnv := func(value float64) (time.Duration, error) {
return time.Duration(value) * time.Second, nil
}
// Register converter.
jsontype.Register("seconds", convert.ToAnyAny(cnv))
// Custom type named "seconds" representing duration in seconds.
data := []byte(`{"type": "seconds", "value": 42}`)
gType := &jsontype.Value{}
err := json.Unmarshal(data, gType)
_ = err // Check error.
fmt.Printf("unmarshalled: %[1]v (%[1]T)\n", gType.GoValue())
// Output:
// unmarshalled: 42s (time.Duration)The registered converter must return an error when conversion of a value from a JSON type to Go type would result in loss of precision, overflow, underflow or conversion is simply impossible. The same way how the github.com/ctx42/convert converter functions work.