map-tree-utils
v1.0.10
Published
Tiny TypeScript utilities to convert between flat Map<string, T> structures and nested tree arrays
Downloads
7
Maintainers
Readme
map-tree-utils
Tiny TypeScript utilities to convert between flat Map<string, T> structures and nested tree arrays.
Install
# npm
npm install map-tree-utils
# yarn
yarn add map-tree-utils
# pnpm
pnpm add map-tree-utils
# bun
bun i map-tree-utilsWhy
When working with hierarchical data, you often face two common tasks:
You receive a nested tree (e.g., from an API or authored JSON) and want to normalize it into a flat Map for fast lookups and updates.
You have a flat structure (e.g., a
Mapkeyed byid) and need to render it as a nested tree for UI or export.
map-tree-utils provides two small, focused helpers with zero runtime dependencies to handle this:
getTree— convert aMap<string, T>(flat) into a nested array of root nodes (tree).getMap— convert a nested array (tree) into aMap<string, AnyObj>(flat).
Written in TypeScript, both functions are simple, predictable, and easy to drop into any frontend or backend project. They save you from writing repetitive boilerplate code while keeping your data handling fast and type-safe.
Quick example
import { getTree, getMap } from "map-tree-utils";
// --- Example: flat Map representing hierarchical data ---
const map = new Map([
["1", { id: "1", name: "Root" }],
["2", { id: "2", name: "Child A", parentId: "1" }],
["3", { id: "3", name: "Child B", parentId: "1" }],
["4", { id: "4", name: "Grandchild", parentId: "2" }],
]);
// Convert flat Map -> nested tree
const tree = getTree(map);
console.log("Nested tree:");
console.log(JSON.stringify(tree, null, 2));
// Convert back: nested tree -> flat Map
const flatMap = getMap(tree);
console.log("Flattened Map, item with id '4':");
console.log(flatMap.get("4"));
// Output: { id: "4", name: "Grandchild", parentId: "2" }
// Get sorted tree: flat Map -> sorted tree
const stortedTree = getTree(map, "children", "parentId", "ord", "asc");
console.log("Sorted tree:");
console.log(JSON.stringify(stortedTree, null, 2));React example
Minimal example
demo:
https://evgen002.github.io/map-tree-demo/
import { useMemo, useState } from "react";
import { getMap, getTree } from "map-tree-utils";
interface Tree {
code: string;
name: string;
childs?: Tree[];
}
const tree: Tree[] = [
{
code: "1",
name: "one",
childs: [
{ code: "1_1", name: "child_one" },
{ code: "1_2", name: "child_two" },
],
},
];
function App() {
const [normalized, setNormalized] = useState(
getMap(tree, "childs", "parentCode", "code")
);
const update = () => {
setNormalized((prev) => {
const map = new Map(prev);
const prevTarget = map.get("1_2");
if (prevTarget) {
map.set("1_2", { ...prevTarget, name: "John" });
return map;
} else {
return prev;
}
});
};
const updatedTree = useMemo(() => {
return getTree(normalized, "childs", "parentCode");
}, [normalized]);
return (
<div className="example">
<h1>Map Tree Utils - DEMO</h1>
<pre>{JSON.stringify(normalized.get("1_2"))}</pre>
<TreeNode tree={updatedTree} />
<button onClick={update}>update</button>
</div>
);
}
function TreeNode({ tree }: { tree: Tree[] }) {
return (
<ul>
{tree.map((node) => (
<li key={node.code}>
{node.name}
{node.childs && node.childs.length > 0 && (
<TreeNode tree={node.childs} />
)}
</li>
))}
</ul>
);
}
export default App;API
getTree<T>(map: Map<string, T>, childKey = "children", parentKey = "parentId"): Array<T & AnyObj>Converts a Map of nodes into a nested array of root nodes.
Parameters
map: Map<string, T>- a Map where each value is a node object containing an identifier and optionally a parent reference.childKey: string- the key to use for children arrays in the output nodes. Default: "children".parentKey: string- the key used on nodes to identify their parent. Default: "parentId".sortBy: string | (a, b) => number- used to return sorted tree
Returns
An array of nodes that are roots (nodes with no parent found in the provided Map). Each node in the returned tree is a shallow copy of the original node with an added children (or custom childKey) array.
Notes
The function creates shallow copies of nodes so the original Map values are not mutated.
If a node references a
parentKey: stringthat does not exist in the Map, the node will be treated as a root.
getMap(tree: AnyObj[], childKey = "children", parentKey = "parentId", idKey = "id"): Map<string, AnyObj>Flattens a nested tree array into a Map<string, AnyObj> keyed by id (or a custom idKey).
Parameters
tree: AnyObj[]- array of tree nodes (roots).childKey: string- property name that holds child nodes. Default: "children".parentKey: string- property name to be assigned to flattened nodes to indicate their parent id. Default: "parentId".idKey: string- property name used in the original nodes to identify them. Default: "id".
Returns
A Map<string, AnyObj> where each key is the stringified id and each value is a shallow copy of the node (the children property is removed). Each child node will have a parentId pointing to its parent in the flattened structure.
Notes
The function will coerce the id value to String() when using it as a Map key.
children arrays are omitted in the flattened node objects.
Performance
Both utilities walk every node exactly once and perform O(N) operations (plus Map lookups which are O(1) amortized). They are suitable for reasonably sized trees used in frontend apps or typical backend data normalization tasks.
License: MIT
