JSON to String Conversion: The Edge Cases That Actually Bite in Production
Every JS developer writes JSON.stringify(data) a hundred times before they ever stop to think about what it's actually doing under the hood. It's one line, it "just works," and most of the time that's a completely fine way to live. Then one day a field goes missing from a payload for no visible reason. Or a service throws TypeError: Converting circular structure to JSON in the middle of a request…
Writing JSON.stringify(data) in JavaScript is a common practice among developers, often without much thought given to its inner workings. While it's true that this line of code usually works fine, there are edge cases that can cause unexpected results in production. This article aims to walk through these edge cases, explain why they happen, and provide guidance on how to handle them.
Firstly, JSON doesn't have native representations for undefined, functions, or Symbol types. When these values are encountered by JSON.stringify, they are dropped silently. The behavior differs depending on whether the value is in an object or an array. For example, when used with an object, the missing fields are completely omitted, whereas in an array, they become null.
Secondly, certain values undergo conversion when serialized. For instance, NaN, Infinity, and -Infinity are all converted to null. Additionally, date objects are converted to their ISO string representation. However, a potential issue arises if a downstream consumer needs to distinguish between NaN and no value. In such cases, the intended value must be encoded before serialization.
Thirdly, date objects are serialized correctly because they support a toJSON() method. This method is called before default handling, allowing for customization in the serialization process. Map and Set objects, however, don't have a toJSON method, and thus, serialize as empty objects. Similarly, BigInt values throw a TypeError since they cannot be serialized directly.
Lastly, circular references in objects cause JSON.stringify to throw a TypeError. This occurs when an object references itself directly or indirectly through a chain of references. This issue is not limited to theoretical cases; it can occur in real-world scenarios involving DOM nodes, ORM entities with back-references, or event emitters attached to data objects. The solution is to strip circular references during serialization using a custom replacer function that tracks already seen objects.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.