Skip to content

Commit

Permalink
feat: allow for skipping properties completely via a special return v…
Browse files Browse the repository at this point in the history
…alue (#64)
  • Loading branch information
RebeccaStevens committed Feb 26, 2022
1 parent 7d5a2ce commit 676f2f6
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
37 changes: 35 additions & 2 deletions docs/deepmergeCustom.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,38 @@ declare module "../src/types" {
}
```

## Default Merging
## Special Actions

We provide a couple of special actions under `utils.actions` that you can use to simplify your custom merge functions.

### Skipping a Property (`utils.actions.skip`)

If you want to skip a property from being included in the result of a merge based on its value or metadata, you can easily do so with this action.

For example, skipping all properties under the key `"skipme"` of type `Date`:

```ts
const customizedDeepmerge = deepmergeCustom({
mergeOthers: (value, utils, meta) => {
if (meta?.key === "skipme") {
const nonDateValues = values.filter((value) => !(value instanceof Date));
if (nonDateValues.length === 0) {
return utils.actions.skip; // Completely skip this property
}

// Don't skip the property completely if a non-Date value was found.
return utils.defaultMergeFunctions.mergeOthers(nonDateValues);
}

// Perform the default merging (see below).
return utils.actions.defaultMerge;
},
});
```

To do this without any special actions would require using a custom `mergeRecords` which would be a bit more complicated.

### Default Merging (`utils.actions.defaultMerge`)

If you do not want to have to explicitly call the default merging function in your custom merge function;
you can just return `utils.actions.defaultMerge`. This will automatically apply the default merging strategy.
Expand Down Expand Up @@ -231,7 +262,9 @@ const customizedDeepmerge = deepmergeCustom({
});
```

### Implicit
Note: When using this action, you cannot change the values upon which the default merging will apply.

#### Implicit Default Merging

You can also set the option `enableImplicitDefaultMerging` to `true` to make it so that if any of your
custom merge functions return `undefined`, then the default merging strategy will automatically be applied.
Expand Down
9 changes: 8 additions & 1 deletion src/deepmerge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const defaultMergeFunctions = {
*/
const actions = {
defaultMerge: Symbol("deepmerge-ts: default merge"),
skip: Symbol("deepmerge-ts: skip"),
} as const;

/**
Expand Down Expand Up @@ -427,11 +428,17 @@ function defaultMergeRecords<
parents: values,
} as unknown as MM);

result[key] = mergeUnknowns<ReadonlyArray<unknown>, U, MF, M, MM>(
const propertyResult = mergeUnknowns<ReadonlyArray<unknown>, U, MF, M, MM>(
propValues,
utils,
updatedMeta
);

if (propertyResult === actions.skip) {
continue;
}

result[key] = propertyResult;
}

/* eslint-enable functional/no-loop-statement, functional/no-conditional-statement */
Expand Down
1 change: 1 addition & 0 deletions src/types/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,6 @@ export type DeepMergeMergeFunctionUtils<
useImplicitDefaultMerging: boolean;
actions: Readonly<{
defaultMerge: symbol;
skip: symbol;
}>;
}>;
25 changes: 25 additions & 0 deletions tests/deepmerge-custom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -664,3 +664,28 @@ test("default merging using shortcut", (t) => {

t.deepEqual(merged, expected);
});

test("skip property", (t) => {
const x = {
foo: { bar: 1, baz: 2, qux: ["a"] },
bar: [1, 2, 3],
};
const y = {
foo: { bar: 3, baz: 4, qux: ["b"] },
bar: [4, 5, 6],
};

const expected = {
foo: { baz: 4, qux: ["a", "b"] },
bar: [1, 2, 3, 4, 5, 6],
};

const customizedDeepmerge = deepmergeCustom({
mergeOthers: (value, utils, meta) =>
meta?.key === "bar" ? utils.actions.skip : utils.actions.defaultMerge,
});

const merged = customizedDeepmerge(x, y);

t.deepEqual(merged, expected);
});

0 comments on commit 676f2f6

Please sign in to comment.