npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@phun-ky/defaults-deep

v1.1.2

Published

Like lodash's _.defaultsDeep, but with array preservation

Downloads

217

Readme

@phun-ky/defaults-deep

Commitizen friendly PRs Welcome SemVer 2.0 npm version issues license size npm GitHub Repo stars codecov build

About

Similar to lodash's defaultsDeep, but without mutating the source object, and no merging of arrays, and no lodash as dependency!

Table of Contents- defaults-deep

Installation

Install the package via npm:

npm i --save @phun-ky/defaults-deep

Usage

ESM

import defaultsDeep from "@phun-ky/defaults-deep";

CommonJS

const defaultsDeep = require("@phun-ky/defaults-deep");

API

function defaultsDeep(...args): Record<PropertyKey, unknown>;

Deeply applies "defaults" from right-to-left sources into a new object, while preserving arrays.

This function mimics the common lodash pattern: _.toArray(arguments).reverse().forEach(x => _.mergeWith(output, x, customizer)), but implemented in vanilla TypeScript with a small, predictable merge core.

Key behaviours

  • Returns a new object (the returned object is created inside the function).
  • Sources are processed right-to-left (reverse()), meaning earlier arguments win: values from the first argument are treated as "defaults" that should not be overwritten by later arguments (because later arguments are merged first).
  • Only object-like sources participate in merging. Non-objects are skipped via isObjectLoose.
  • Uses mergeWith for the deep merge logic.
  • Arrays are preserved by replacement: if a source value is an array, it replaces the destination value at that key (rather than being merged element-by-element).

Parameters

| Parameter | Type | Description | | --------- | ------------ | ------------------------------------------------------------------------- | | ...args | unknown[] | A list of potential default/source values. Non-object values are ignored. |

Returns

Record<PropertyKey, unknown>

A new object containing the merged result.

Examples

defaultsDeep(
  { a: 1, nested: { x: 1 }, list: [1] },
  { a: 2, nested: { y: 2 }, list: [2] }
);
// => { a: 1, nested: { x: 1, y: 2 }, list: [1] }
// (earlier args win; arrays preserved by replacement)
defaultsDeep({ opts: { retry: 3 } }, null, { opts: { timeout: 1000 } });
// => { opts: { retry: 3, timeout: 1000 } }
// (non-object sources are ignored)

Differences from lodash (_.defaultsDeep / _.mergeWith pattern)

This package is inspired by lodash's common _.defaultsDeep approach (often implemented as _.toArray(arguments).reverse() + _.mergeWith(...)), but it is not a drop-in, byte-for-byte compatible clone. The goal here is to cover the common "configuration defaults" use case with a much smaller, dependency-free implementation. For typical plain objects (JSON-like data) and arrays, the results should match what you expect from the lodash approach.

The biggest difference is the underlying merge engine. Lodash's mergeWith is a mature, highly general deep-merge with lots of special-case behaviour for many JavaScript value types and edge cases. This implementation intentionally keeps the default rules conservative: it only deep-merges plain objects and treats most other things as replace-by-assignment. That means values like arrays, dates, maps/sets, functions, class instances, and other non-plain objects are not recursively merged unless you explicitly handle them via a customizer.

Array behaviour is also deliberately simpler and more explicit. Lodash's merge behaviour around arrays can be nuanced depending on the function and scenario; in this implementation, arrays are preserved by replacement (the source array overwrites the destination array) rather than being merged element-by-element. This matches the "array preservation" intent for defaults/config objects, but if you expect lodash-style index-wise array merging or concatenation in some cases, you'll need to provide your own customizer.

Another difference is how non-object inputs are treated. Lodash tends to be extremely permissive about odd inputs and will try hard to produce "something reasonable" even when sources are primitives or exotic objects. This implementation focuses on predictable behaviour for configuration merging: non-object sources are typically ignored (or treated as simple replacements at a property level), and only "object-like" values participate meaningfully in deep merging. If you pass primitives/functions as top-level sources, don't expect identical behaviour to lodash across all cases.

Finally, because this package is written in TypeScript with a strict API surface, you may notice differences at compile time even when runtime behaviour is similar. The functions lean on explicit type guards and object-shape constraints rather than lodash's "accept almost anything" philosophy. The payoff is a smaller dependency footprint and clearer semantics for the common defaults use case, at the cost of not matching lodash's full breadth of type handling and edge-case compatibility.

Notice

This project is a fork of https://github.com/nodeutils/defaults-deep. Original work © 2016 Drew Llewellyn, licensed ISC (see LICENSE-ISC). Modifications © 2026 Alexander Vassbotn Røyne-Helgesen, licensed MIT (see LICENSE-MIT).

Contributing

Want to contribute? Please read the CONTRIBUTING.md and CODE_OF_CONDUCT.md

License

This project is maintained by Alexander Vassbotn Røyne-Helgesen and is based on original work by Drew Llewellyn ([email protected], https://drew.pro). The original upstream code is licensed under the ISC License, and the modifications/changes in this fork are licensed under the MIT License.

Changelog

See the CHANGELOG.md for details on the latest updates.

Sponsor me

I'm an Open Source evangelist, creating stuff that does not exist yet to help get rid of secondary activities and to enhance systems already in place, be it documentation or web sites.

The sponsorship is an unique opportunity to alleviate more hours for me to maintain my projects, create new ones and contribute to the large community we're all part of :)

Support me on GitHub Sponsors.

p.s. Ukraine is still under brutal Russian invasion. A lot of Ukrainian people are hurt, without shelter and need help. You can help in various ways, for instance, directly helping refugees, spreading awareness, putting pressure on your local government or companies. You can also support Ukraine by donating e.g. to Red Cross, Ukraine humanitarian organisation or donate Ambulances for Ukraine.