Json — Safe Parsing & Stringifying
1.75 kB minified + gzipped
Almost every network boundary, webhook handler, cache layer, and browser storage adapter serializes
and deserializes JSON. Yet JavaScript’s built-in JSON.parse and JSON.stringify are designed
around runtime exceptions and untyped return values that undermine TypeScript pipelines:
JSON.parsethrowsSyntaxErrorand returnsany: Passing a truncated payload or an HTML502 Bad Gatewayerror page toJSON.parsethrows an unhandledSyntaxError. Even when parsing succeeds, its return type isany, which silently disables TypeScript type checking downstream.JSON.stringifythrowsTypeErroronBigIntand circular references: If an object contains abigintfield (such as a 64-bit database ID or cent balance) or a circular object reference,JSON.stringifythrows a runtimeTypeErrorand crashes the request.JSON.stringifysilently returnsundefinedon un-serializable inputs: Passingundefined, a function, or aSymboldirectly toJSON.stringifydoes not return astring— it returnsundefined, which can corrupt storage writes or message queues expecting valid JSON text.
Json wraps both operations in typed Result containers, turning syntax failures and
un-serializable values into explicit Err(SyntaxError) and Err(TypeError) values that compose
linearly inside pipe.
Safe Parsing with Json.parse
Section titled “Safe Parsing with Json.parse”Json.parse<T = unknown>(text) parses a JSON string and returns Result<SyntaxError, T>. By
default, the success value is typed as unknown rather than any, prompting you to validate the
structure or supply an explicit domain interface before accessing fields. If the input string is
malformed, Json.parse catches the exception and returns Err(SyntaxError):
Because Json.parse returns a Result, you can chain structural validation steps directly after
parsing using Result.chain or Result.ensure:
Safe Serialization with Json.stringify
Section titled “Safe Serialization with Json.stringify”Json.stringify(value, replacer?, space?) serializes any JavaScript value into a JSON string and
returns Result<TypeError, string>.
It protects against all three failure modes of native JSON.stringify:
- Circular object references: Caught and returned as
Err(TypeError). - Unsupported
BigIntvalues: Caught and returned asErr(TypeError)(unless converted by a customreplacer). - Un-serializable top-level values (
undefined, functions, symbols): Instead of returningundefined,Json.stringifyreturnsErr(TypeError("Value is not JSON serializable")).
If your payload legitimately contains bigint values, you can pass a custom replacer function as
the second argument to serialize them as strings:
Pipeline Composition
Section titled “Pipeline Composition”Here is an end-to-end payment webhook processor that parses an incoming JSON request body, validates the required payload fields, computes a settlement summary, and serializes the response back to a JSON string with a unified error channel:
Problems it solves
Section titled “Problems it solves”- Safe parsing of untrusted webhook and API payloads (
Json.parse): Calling nativeJSON.parse()on malformed HTTP request bodies or corrupted cache entries throws runtime exceptions and returns untypedany.Json.parse<T>returnsResult<SyntaxError, T>(defaultingTtounknown), turning syntax errors into explicit failure values. - Resilient serialization without runtime crashes (
Json.stringify): Serializing dynamic objects tolocalStorage, message queues, or HTTP responses throwsTypeErrorwhen objects contain circular references orBigIntvalues, and silently returnsundefinedwhen givenundefinedor functions.Json.stringifyreturnsResult<TypeError, string>, guaranteeing that everyOkcontains a valid JSON string and every failure is captured as anErr(TypeError). - Linear pipeline composition: Raw JSON text can be parsed, validated with
Result.chain, transformed, and re-serialized inside a singlepipeflow withouttry/catchblocks or mutableletvariables.