Skip to content

Commit

Permalink
Avoid copying non-enumerable and/or symbol keys in cloneDeep. (#4052)
Browse files Browse the repository at this point in the history
#4039 (comment)

The previous fclone implementation also did not preserve non-enumerable
or non-string keys, so this is not a breaking change.

The Date case was also a bit overzealous, since there are no actual use cases
in this codebase that require Date objects to be duplicated, rather than simply
passing them through.

If we're missing any cases that anyone cares about, we can easily expand the
switch-case coverage in the future.
  • Loading branch information
benjamn committed Oct 24, 2018
1 parent 7fa0d85 commit 5874bec
Showing 1 changed file with 3 additions and 25 deletions.
28 changes: 3 additions & 25 deletions packages/apollo-utilities/src/util/cloneDeep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,15 @@ function cloneDeepHelper<T>(val: T, seen: Map<any, any>): T {
return copy;
}

case "[object Date]":
return new Date(+val) as T & Date;

case "[object Object]": {
if (seen.has(val)) return seen.get(val);
// High fidelity polyfills of Object.create and Object.getPrototypeOf are
// possible in all JS environments, so we will assume they exist/work.
const copy = Object.create(Object.getPrototypeOf(val));
seen.set(val, copy);

if (typeof Object.getOwnPropertyDescriptor === "function") {
const handleKey = function (key: string | symbol) {
const desc = Object.getOwnPropertyDescriptor(val, key);
// If the property is backed by a getter function, this code turns it
// into a simple value property, though other descriptor properties like
// enumerable, writable, and configurable will be preserved.
desc.value = cloneDeepHelper((val as any)[key], seen);
delete desc.get;
delete desc.set;
Object.defineProperty(copy, key, desc);
};
Object.getOwnPropertyNames(val).forEach(handleKey);
if (typeof Object.getOwnPropertySymbols === "function") {
Object.getOwnPropertySymbols(val).forEach(handleKey);
}
} else {
Object.keys(val).forEach(key => {
copy[key] = cloneDeepHelper((val as any)[key], seen);
});
}

Object.keys(val).forEach(key => {
copy[key] = cloneDeepHelper((val as any)[key], seen);
});
return copy;
}

Expand Down

0 comments on commit 5874bec

Please sign in to comment.