@lumirelle/defu
v1.2.1
Published
Recursively assign default properties. Lightweight and Fast!
Readme
🌊 defu
Assign default properties, recursively. Lightweight and Fast.
A fork of unjs/defu with some improvements:
- Nullish values support
- Reverse array merging order support
Install
Install package:
# yarn
yarn add defu
# npm
npm install defu
# pnpm
pnpm install defuUsage
import { defu } from "defu";
const options = defu(object, ...defaults);Leftmost arguments have more priority when assigning defaults.
Arguments
- object (Object): The destination object.
- source (Object): The source object.
import { defu } from "defu";
console.log(defu({ a: { b: 2 } }, { a: { b: 1, c: 3 } }));
// => { a: { b: 2, c: 3 } }Using with CommonJS
const { defu } = require("defu");Custom Merger
Sometimes default merging strategy is not desirable. Using createDefu we can create a custom instance with different merging strategy.
This function accepts obj (source object), key and value (current value) and should return true if applied custom merging.
Example: Sum numbers instead of overriding
import { createDefu } from "defu";
const ext = createDefu((obj, key, value) => {
if (typeof obj[key] === "number" && typeof value === "number") {
obj[key] += value;
return true;
}
});
ext({ cost: 15 }, { cost: 10 }); // { cost: 25 }Use with nullish values
By default, defu will skip nullish values in source object (null and undefined) when merging, so that the default values are preserved.
import { defu } from "defu";
defu(
{
name: null,
age: undefined,
country: "France",
},
{
name: "Lumirelle",
age: 30,
},
);
/*
{
name: 'Lumirelle',
age: 30,
country: 'France'
}
*/But if you want to consider nullish value as valid one, you can create a custom defu instance with option acceptNullish set to true.
import { createDefu } from "defu";
const defuWithNull = createDefu(undefined, { acceptNullish: true });
defuWithNull(
{
name: null,
age: undefined,
country: "France",
},
{
name: "Lumirelle",
age: 30,
},
);
/*
{
name: null,
age: undefined,
country: 'France'
}
*/Use with arrays
By default, defu will concat arrays when merging.
The merged array will have the values from source object first, followed by the values from default object.
import { defu } from "defu";
defu(
{
tags: ["javascript", "web"],
},
{
tags: ["programming", "development"],
},
);
/*
The default array values are appended after the source array values:
{
tags: ['javascript', 'web', 'programming', 'development']
}
*/If you want to reverse the order, you can create a custom defu instance with option reverseArrayOrder set to true:
import { createDefu } from "defu";
const defuReverseArray = createDefu(undefined, {
reverseArrayOrder: true,
});
defuReverseArray(
{
tags: ["javascript", "web"],
},
{
tags: ["programming", "development"],
},
);
/*
The default array values are prepended before the source array values:
{
tags: ['programming', 'development', 'javascript', 'web']
}Function Merger
Using defuFn, if user provided a function, it will be called with default value instead of merging.
It can be useful for default values manipulation.
Example: Filter some items from defaults (array) and add 20 to the count default value.
import { defuFn } from "defu";
defuFn(
{
ignore: (val) => val.filter((item) => item !== "dist"),
count: (count) => count + 20,
},
{
ignore: ["node_modules", "dist"],
count: 10,
},
);
/*
{
ignore: ['node_modules'],
count: 30
}
*/Note: if the default value is not defined, the function defined won't be called and kept as value.
Array Function Merger
defuArrayFn is similar to defuFn but only applies to array values defined in defaults.
Example: Filter some items from defaults (array) and add 20 to the count default value.
import { defuArrayFn } from "defu";
defuArrayFn(
{
ignore: (val) => val.filter((i) => i !== "dist"),
count: () => 20,
},
{
ignore: ["node_modules", "dist"],
count: 10,
},
);
/*
{
ignore: ['node_modules'],
count: () => 20
}
*/Note: the function is called only if the value defined in defaults is an aray.
Remarks
objectanddefaultsare not modified- Nullish values (
nullandundefined) are skipped by default. If you want to consider them as valid values, see Use with nullish values section. - Assignment of
__proto__andconstructorkeys will be skipped to prevent security issues with object pollution. - Will concat
arrayvalues (if default property is defined)
console.log(defu({ array: ["b", "c"] }, { array: ["a"] }));
// => { array: ['b', 'c', 'a'] }Type
We expose Defu as a type utility to return a merged type that follows the rules that defu follows.
import type { Defu } from 'defu'
type Options = Defu<{ foo: 'bar' }, [{}, { bar: 'baz' }, { something: 42 }]>
// returns { foo: 'bar', bar: 'baz', 'something': 42 }License
MIT. Made with 💖
