Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map and Set merging support #204

Open
RebeccaStevens opened this issue Sep 17, 2020 · 1 comment
Open

Map and Set merging support #204

RebeccaStevens opened this issue Sep 17, 2020 · 1 comment

Comments

@RebeccaStevens
Copy link

RebeccaStevens commented Sep 17, 2020

I'm not sure if this is in the scope of this library or not but I think it would be a good to have support for merging Sets and Maps out of the box.

I needed support for this functionality for a project I'm working on and so I wrote my own wrapper for this lib to add support. I thought I should drop the code snippet here in case anyone else needed this functionality.

import deepMergeLib from 'deepmerge';
import isPlainObject from 'is-plain-object';

export function mergeMaps<K, V>(
  maps: ReadonlyArray<ReadonlyMap<K, V>>,
  deep = false
): Map<K, V> {
  return maps.reduce<Map<K, V>>((mutableCarry, current) => {
    for (const [key, value] of current.entries()) {
      const currentValue = mutableCarry.get(key);
      mutableCarry.set(
        key,
        deep && typeof value === 'object' && typeof currentValue === 'object'
          ? ((deepMerge([
              (currentValue as unknown) as object,
              (value as unknown) as object,
            ]) as unknown) as V)
          : value
      );
    }
    return mutableCarry;
  }, new Map<K, V>());
}

export function mergeSets<V>(sets: ReadonlyArray<ReadonlySet<V>>): Set<V> {
  return sets.reduce<Set<V>>((mutableCarry, current) => {
    for (const value of current.values()) {
      mutableCarry.add(value);
    }
    return mutableCarry;
  }, new Set<V>());
}

export function deepMerge<T extends object>(
  values: ReadonlyArray<T>,
  options = { mergeMaps: true, mergeSets: true }
): T {
  const [mergeAsMaps, mergeAsSets] =
    (options.mergeMaps || options.mergeSets) && values.length > 0
      ? values.reduce(
          (carry, value) => [
            carry[0] && value instanceof Map,
            carry[1] && value instanceof Set,
          ],
          [options.mergeMaps, options.mergeSets]
        )
      : [false, false];

  if (mergeAsSets) {
    return mergeSets(values as any) as T;
  }
  if (mergeAsMaps) {
    return mergeMaps(values as any, true) as T;
  }

  return deepMergeLib.all(values as Array<T>, {
    customMerge: () => (a: T, b: T) => deepMerge<T>([a, b], options),
    isMergeableObject: (value: object) =>
      (options.mergeSets && value instanceof Set) ||
      (options.mergeMaps && value instanceof Map) ||
      isPlainObject(value),
    clone: false,
  }) as T;
}
@RebeccaStevens
Copy link
Author

I've made my own package now that has builtin support for set and map merging as well as some other benefits. deepmerge-ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant