Package for json stringify objects without losing data types
npm install json-storage-formatterA lightweight solution to format complex JavaScript objects for string-based storage systems without losing their types. π
``ts
const userProfile = {
id: 42,
createdAt: new Date('2024-10-01T10:30:00Z'),
preferences: new Map([
['theme', 'dark'],
['languages', new Set(['en', 'es'])],
]),
};
console.log(JSON.stringify(userProfile, null, 2));
`
Console Output:
`json`
{
"id": 42,
"createdAt": "2024-10-01T10:30:00.000Z",
"preferences": {}
}
When working with tools like localStorage, sessionStorage, AsyncStorage, or even databases like Redis or PostgreSQL (JSON columns), we often need to store application state or configuration objects as strings using JSON.stringify.
_But thereβs a catch!:_
JSON.stringify has no idea what to do with values like Date, Map, or Set...
It just flattens them into empty objects or strings, making you lose the original data types or the entire structure.
---
Exposes two simple functions:
1. formatToStore(value) β safely prepares your data for storage, returning a JSON string representation.formatFromStore(value)
2. β restores it to the exact original shape and types.
As simple as that.
---
Letβs create a hook that syncs localStorage with React state:
`ts
import { formatToStore, formatFromStore } from 'json-storage-formatter';
type DashboardConfig = {
theme: 'light' | 'dark' | 'system';
widgets: Map
hiddenWidgets: Set
lastCustomizedAt: Date;
};
const useDashboardConfig = () => {
const [config, setConfig] = useState
const json = localStorage.getItem('dashboard-config');
if (json) return formatFromStore
return getDefaultDashboardConfig();
});
const saveConfig = (newConfig: DashboardConfig) => {
localStorage.setItem('dashboard-config', formatToStore(newConfig));
setConfig(newConfig);
};
return { config, saveConfig };
};
// Even if the config contains Maps, Sets, or Dates, they will be preserved.
const example: DashboardConfig = {
theme: 'dark',
widgets: new Map([
['weather', { location: 'New York', units: 'metric' }],
['stocks', { symbols: ['AAPL', 'GOOGL'] }],
]),
hiddenWidgets: new Set(['news']),
lastCustomizedAt: new Date(),
};
`
---
This pattern is common in dashboards, where filters are shared via URL.
You can safely serialize complex filters (with Dates, Sets, Maps, etc.) and encode them for sharing.
`tsx
import { formatToStore, formatFromStore } from 'json-storage-formatter';
type DashboardQuery = {
dateRange: { from: Date; to: Date };
selectedCategories: Set
additionalSettings: Map
};
const useUrlQuery = () => {
const [query, setQuery] = useState
const params = new URLSearchParams(location.search);
const storedQuery = params.get('query');
if (storedQuery) {
// decode from base64 and restore types
return formatFromStore
}
return getDefaultDashboardQuery();
});
const updateQuery = (newQuery: DashboardQuery) => {
const encoded = btoa(formatToStore(newQuery));
// encode the JSON as base64 to make it URL-safe
// avoids breaking query strings with +, /, or = characters
window.history.replaceState(null, '', \${location.pathname}?query=\${encoded});
setQuery(newQuery);
};
return { query, updateQuery };
};
`
The examples above use React, but the library itself is framework-agnostic
and can be used anywhere in JavaScript or TypeScript projects.
---
This becomes incredibly powerful when your app needs to sync complex state
to a string-based storage layer β like when syncing to localStorage, Redis, or a shared dashboard URL.
Instead of being limited by what JSON can handle,
you can now serialize any structure β Maps, Sets, nested objects, or Dates β
and restore it back without losing context or meaning.
---
Under the hood, formatToStore adds small metadata markers to every special value.
Each piece of data gets a structure like this:
`json`
{
"$t": "map",
"$v": [["key", { "$t": "date", "$v": "2024-10-01T10:30:00.000Z" }]]
}
The $t field stores the type, and $v holds the actual value. formatFromStore
When using , it reads that metadata and recreates your data structure
exactly as it was before β even if itβs deeply nested.
Resulting in:
`ts`
new Map([['key', new Date('2024-10-01T10:30:00.000Z')]]);
---
Converts any value into a JSON-safe structure with internal type metadata.
`ts`
const objectWithMetadata = formatToStore(object);
Restores the serialized object back to its original types.
`ts`
const result = formatFromStore
Both functions work directly with strings,
so you can safely use them with localStorage, AsyncStorage, or URLs.
---
| Function | Description | Example |
| ------------- | ---------------------------------------- | ----------------------------- |
| isNil | Checks if value is null or undefined | isNil(null); // true |isNumber(42); // true
| isNumber | Checks if value is a number | |isBoolean(false); // true
| isBoolean | Checks if value is a boolean | |isString('hi'); // true
| isString | Checks if value is a string | |isDate(new Date()); // true
| isDate | Checks if value is a Date | |
---
| Behavior | JSON.stringify | json-storage-formatter |
| ------------- | --------------- | ------------------------ |
| Date | Becomes string | β
Restored as Date |
| Set | Lost completely | β
Restored as Set |
| Map | Lost completely | β
Restored as Map |
| Undefined | Omitted | β
Restored as undefined |
| Regexp | Lost completely | β
Restored as RegExp |
| Error | Lost completely | β
Restored as Error |
---
`bash`
npm install json-storage-formatter
or
`bash``
yarn add json-storage-formatter
---
π NPM: json-storage-formatter
Serialize, store, and restore any JavaScript data type without losing its identity β lightweight, fast. β¨