Skip to content

Commit

Permalink
feat: add 'deepCopy' util
Browse files Browse the repository at this point in the history
  • Loading branch information
trevor-anderson committed May 12, 2023
1 parent c1d818e commit 10107f1
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/utils/deepCopy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Primitive } from "type-fest";

/**
* This function creates a same-type deep copy of the input without using methods
* like `JSON.parse(JSON.stringify(input))` which can't handle certain types of
* data like `undefined`, `null`, `Date`, `Map`s, etc.
*
* > Note: The `structuredClone` Web API method is a better alternative to this
* implementation, but as of May 2023, it's only supported in the very latest
* versions of some browsers like Chrome and Safari, _and_ the Nodejs version
* used in the dev-env would have to be bumped to at least v17 as well. Until
* these compatibility issues are resolved, use this function instead.
*/
export const deepCopy = <T extends DeepCopyInput>(input: T): T => {
return typeof input === "bigint" ||
typeof input === "boolean" ||
typeof input === "number" ||
typeof input === "string" ||
typeof input === "symbol" ||
typeof input === "undefined" ||
input === null
? input // else typeof input is "object"
: input instanceof Date
? (new Date(input.getTime()) as T)
: input instanceof Map
? (new Map(Array.from(input).map(([key, value]) => [deepCopy(key), deepCopy(value)])) as T)
: input instanceof Set
? (new Set(Array.from(input).map((item) => deepCopy(item))) as T)
: Array.isArray(input)
? (input.map((item) => deepCopy(item)) as T)
: (Object.fromEntries(
Object.entries(input).map(([key, value]) => [key, deepCopy(value)])
) as T);
};

export type DeepCopyInput =
| Primitive
| Date
| Map<DeepCopyInput, DeepCopyInput>
| Set<DeepCopyInput>
| Array<DeepCopyInput>
| Record<PropertyKey, any>;

0 comments on commit 10107f1

Please sign in to comment.