Skip to main content

defaultsDeep()

defaultsDeep<T>(object, ...sources): T

Recursively assigns source properties to destination only where destination is undefined.

note

Only undefined values are replaced. null values are preserved.


Type Parametersโ€‹

T: T extends Record<string, unknown>โ€‹

The type of the destination object.


Parametersโ€‹

object: Tโ€‹

The destination object.

sources: ...Record<string, unknown>[]โ€‹

The source objects.


Returns: Tโ€‹

A new object with deep defaults applied (does not mutate original).


Sinceโ€‹

2.0.0


Noteโ€‹

Arrays are replaced, not merged.


Performanceโ€‹

O(nร—m) where n = total properties, m = depth.


Also known asโ€‹

defaultsDeep (Lodash, es-toolkit) ยท mergeDeepRight (Ramda) ยท โŒ (Remeda, Radashi, Effect, Modern Dash, Antfu)


Exampleโ€‹

const target = { a: { b: undefined, c: 3 } };
const source = { a: { b: 2, d: 4 }, e: 5 };

defaultsDeep(target, source);
// => { a: { b: 2, c: 3, d: 4 }, e: 5 }

// null is preserved (not undefined)
defaultsDeep({ a: { b: null } }, { a: { b: 'fallback' } });
// => { a: { b: null } }

// Arrays are replaced, not merged
defaultsDeep({ items: undefined }, { items: [1, 2] });
// => { items: [1, 2] }

How it works?โ€‹

Recursively fills in undefined properties at all nesting levels.

Deep Traversalโ€‹

defaults vs defaultsDeepโ€‹

defaultsdefaultsDeep
ScopeTop-level onlyAll nesting levels
ObjectsReplacedMerged recursively

Use Casesโ€‹

Configuration Merging with nested defaults ๐Ÿ“Œโ€‹

Merge user configuration with default values recursively. Essential for application configuration systems.

import { defaultsDeep } from "pithos/arkhe/object/defaults-deep";

const defaultConfig = {
server: {
port: 3000,
host: "localhost",
ssl: { enabled: false, cert: null },
},
logging: {
level: "info",
format: "json",
},
cache: {
enabled: true,
ttl: 3600,
},
};

const userConfig = {
server: {
port: 8080,
ssl: { enabled: true },
},
logging: {
level: "debug",
},
};

const config = defaultsDeep(userConfig, defaultConfig);
console.log(config);
// {
// server: { port: 8080, host: "localhost", ssl: { enabled: true, cert: null } },
// logging: { level: "debug", format: "json" },
// cache: { enabled: true, ttl: 3600 }
// }

Theme Customization with partial overrides ๐Ÿ“Œโ€‹

Apply partial theme overrides to default theme. Critical for customizable UI systems.

import { defaultsDeep } from "pithos/arkhe/object/defaults-deep";

const defaultTheme = {
colors: {
primary: "#007bff",
secondary: "#6c757d",
background: "#ffffff",
text: "#212529",
},
spacing: {
small: "8px",
medium: "16px",
large: "24px",
},
typography: {
fontFamily: "Arial, sans-serif",
fontSize: { base: "16px", heading: "24px" },
},
};

const darkThemeOverrides = {
colors: {
background: "#1a1a1a",
text: "#f0f0f0",
},
};

const darkTheme = defaultsDeep(darkThemeOverrides, defaultTheme);
console.log(darkTheme.colors);
// { primary: "#007bff", secondary: "#6c757d", background: "#1a1a1a", text: "#f0f0f0" }

API Request Options with defaultsโ€‹

Apply default options to API requests. Important for consistent API interactions.

import { defaultsDeep } from "pithos/arkhe/object/defaults-deep";

const defaultOptions = {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
timeout: 30000,
retry: { attempts: 3, delay: 1000 },
};

function createRequest(url: string, options: Partial<typeof defaultOptions> = {}) {
const finalOptions = defaultsDeep(options, defaultOptions);

return {
url,
...finalOptions,
};
}

const request = createRequest("/api/users", {
headers: { Authorization: "Bearer token" },
retry: { attempts: 5 },
});

console.log(request.headers);
// { "Content-Type": "application/json", Accept: "application/json", Authorization: "Bearer token" }
console.log(request.retry);
// { attempts: 5, delay: 1000 }