typescript
25 lines · 7 steps
Flattening nested objects into dotted keys
A recursive reducer collapses a nested object into a single-level map with dot-delimited paths.
Explained by
highlit
1type Flatten = Record<string, unknown>;
2
3function isPlainObject(value: unknown): value is Record<string, unknown> {
4 return (
5 typeof value === "object" &&
6 value !== null &&
7 !Array.isArray(value) &&
8 (Object.getPrototypeOf(value) === Object.prototype ||
9 Object.getPrototypeOf(value) === null)
10 );
11}
12
13export function flatten(source: Record<string, unknown>, prefix = ""): Flatten {
14 return Object.entries(source).reduce<Flatten>((acc, [key, value]) => {
15 const path = prefix ? `${prefix}.${key}` : key;
16
17 if (isPlainObject(value) && Object.keys(value).length > 0) {
18 Object.assign(acc, flatten(value, path));
19 } else {
20 acc[path] = value;
21 }
22
23 return acc;
24 }, {});
25}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A strict type guard prevents recursing into arrays or class instances you meant to keep whole.
- 2Recursion plus an accumulated prefix turns tree structure into flat, path-addressable keys.
- 3Treating empty objects as leaves avoids silently dropping keys that have no children.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
Intermediate
8 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core'; interface Preferences { theme: 'light' | 'dark';
A signal-based preferences store in Angular
signals
state-management
persistence
Intermediate
7 steps
typescript
import { useEffect, useState } from "react"; interface Section { id: string;
Building a scroll-spy hook in React
custom-hooks
intersectionobserver
dom-observation
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/flattening-nested-objects-into-dotted-keys-explained-typescript-0b63/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.