Here comes SuperJSON

Nicholas Dobie
Dec 16, 2019 · 4 min read

After years of working on advanced JavaScript applications I’ve learn a lot. As my applications have grown more complex with more data needing to be shifted around and saved. I’ve found a painful truth, JSON isn’t good enough. With more complex data being used in applications, I’ve had to start writing converters to turn the data into something that can be used by JSON and then write more converters to turn the JSON back into my complex data. This has lead to some really ugly functions, that have become nightmares to maintain.

Well I decided that I could create a better solution, so I did. There were a few key things that I wanted my solution to do. One, produce valid JSON code so that other application not using the library could still parse the data. Two, support more of the built-in JavaScript classes like Date, Map, and Set. Three, allow for custom classes. The result was SuperJSON and after a few months of testing and validating I feel it is ready for sharing.

SuperJSON is released under the MIT license and the source code is available on GitHub.

Using SuperJSON

A code example of using SuperJSON to encode and decode a date.
A code example of using SuperJSON to encode and decode a date.
Simple example of SuperJSON

The two main functions of SuperJSON are SuperJSON.parse and SuperJSON.stringify which align with their JSON counterparts making SuperJSON a true drop-in replacement for JSON. Out of the box it supports primitives, arrays, plain objects, Dates, Maps, Sets, and TypedArrays with more built-ins coming.

Behind the scenes, SuperJSON replaces instances that aren’t supported natively by JSON with an object using the keys "__sj_type" and "__sj_value" when stringifying. When parsing it looks for an object containing those keys and uses them to recreate a similar instance. Type informs what class to use for the recreation and the value is JSON safe data that can be used to recreate the instance.

Nested Data

A code example of nesting dates in a set and using SuperJSON to encode and decode all data.
A code example of nesting dates in a set and using SuperJSON to encode and decode all data.
Example showing nested data

A huge issue I have had with custom serializers and deserializers was that they were directly tied to the data structure. This made any change to the data structure require a change to the serializers and deserializers. To get around this, SuperJSON instead walks through the data structure looking at each instance in isolation. The walk method meant that SuperJSON doesn’t need to know anything about the data structure or what to do with nested data. Instead it just knows what to do with that specific instance.

Custom Classes

Code example showing how to register a custom class.
Code example showing how to register a custom class.
Registering a custom class

For a custom class all SuperJSON needs is the constructor, a serializer function, and a deserializer function. The serializer and deserializer can be written as part of class itself to make it easier to maintain. When registering a class with SuperJSON it will look for a public toJSONValue method and a static public fromJSONValue method for the serializer and deserializer respectively. The serializer only needs to return the data need to recreate the instance, the returned data will be ran through SuperJSON so there is no requirement for the data to be JSON-safe. The deserializer will receive a restored version of what was returned from the serializer and should do its best to recreate the original instance. Once you have completed the class you simply need to pass it to SuperJSON.register and your done.

Code example showing how to pass custom serializers and deserializers to register.
Code example showing how to pass custom serializers and deserializers to register.
Using register options

In some situations, you may not be able to update the class or want to provide custom serializers or deserializers. SuperJSON.register accepts an object of options as the second argument that you can specify the name, toJSONValue method, and fromJSONValue method. You can pass as many options as needed. This is actually how SuperJSON registers the core JavaScript classes like Date behind the scenes. By default SuperJSON will try to infer the name field but this can have naming conflicts or could be clobbered by obfuscators like UglifyJS or Terser. In these cases you can manually set the name to prevent issues.

What’s next for SuperJSON?

One Dead Pixel

Web development tutorials and discussions.

Nicholas Dobie

Written by

One Dead Pixel

Web development tutorials and discussions.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade