Safe Flat Utilities
safe-flat is a JavaScript/TypeScript utility library designed for safely flattening and unflattening deeply nested objects. Its primary function, `flatten`, converts a multi-level object into a single-level object, using a configurable delimiter (defaulting to '.'). A key feature is its robust handling of circular references, which it replaces with the `[Circular]` string during flattening to prevent infinite recursion and serialization issues. The companion function, `unflatten`, reconstructs the original nested object structure from a flattened representation, treating `[Circular]` markers as literal string values. The current stable version, 2.1.0, is distributed with TypeScript types, enhancing developer experience. It appears to have a stable, though infrequent, release cadence, focusing on reliability for object serialization and deserialization tasks by mitigating common pitfalls like circular references.
Common errors
-
TypeError: Cannot read properties of undefined (reading '0') / TypeError: Cannot set properties of undefined (setting 'b') / Object reconstruction incorrect
cause The delimiter used in `unflatten` does not match the delimiter used during `flatten`, or the input flattened object structure is not as expected.fixVerify that the `delimiter` argument passed to `unflatten` is the same as the one used for `flatten`. Inspect the flattened object's keys to ensure they follow the expected delimited path format. -
Unflattened object contains `"[Circular]"` strings instead of reconstructed object references.
cause This is the intended behavior of `safe-flat`. The library does not reconstruct circular references during the `unflatten` operation; it preserves `[Circular]` as a literal string.fixNo fix within `safe-flat` itself. If true circular reference restoration is a requirement, an alternative serialization/deserialization strategy or library must be used.
Warnings
- gotcha The `flatten` function replaces circular references with the literal string `[Circular]` to prevent infinite loops. When `unflatten` is used, these `[Circular]` markers are treated as plain string values and the original circular object references are NOT reconstructed. This is by design but can be misunderstood by users expecting full deserialization of circular graphs.
- gotcha Consistency in the `delimiter` is crucial. If `flatten` is called with a custom delimiter (e.g., '_') and `unflatten` is later called without specifying that same delimiter (thus using the default '.'), the `unflatten` operation will fail to correctly reconstruct the object structure, resulting in a malformed output.
- gotcha While `safe-flat` handles circular references, it does not perform deep cloning or custom serialization for other complex nested types (e.g., `Date` objects, `RegExp`, custom class instances). These values will be preserved directly if they are terminal leaves in the flattened structure, but `safe-flat` doesn't provide specific mechanisms for their custom serialization or deserialization.
Install
-
npm install safe-flat -
yarn add safe-flat -
pnpm add safe-flat
Imports
- flatten
const { flatten } = require('safe-flat');import { flatten } from 'safe-flat'; - unflatten
const { unflatten } = require('safe-flat');import { unflatten } from 'safe-flat'; - Types
import type { FlattenedObject, UnflattenedObject } from 'safe-flat';
Quickstart
import { flatten, unflatten } from 'safe-flat';
const original = {
a: {
b: {
c: [{ val: 'one' }, { val: 'two' }],
d: 'three'
},
e: 'four',
}
};
original.a.b.f = original.a.b; // Introduce a circular reference
original.a.b.c.push(original.a); // Another circular reference
console.log('Original Object:', JSON.stringify(original, null, 2));
const flat = flatten(original);
console.log('\nFlattened Object (default delimiter):', JSON.stringify(flat, null, 2));
const underscoreFlat = flatten(original, '_');
console.log('\nFlattened Object (underscore delimiter):', JSON.stringify(underscoreFlat, null, 2));
const unflat = unflatten(flat);
console.log('\nUnflattened Object:', JSON.stringify(unflat, null, 2));
// Note: Circular references are not re-created; '[Circular]' strings remain.