Skip to content

Commit

Permalink
types and documentation cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
planttheidea committed Oct 1, 2022
1 parent f0cb431 commit a4a8d67
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 5 deletions.
91 changes: 91 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ A [blazing fast](#benchmarks) deep object copier
- [`copy`](#copy)
- [`copyStrict`](#copystrict)
- [`createCopier`](#createcopier)
- [Copier state](#copier-state)
- [`cache`](#cache)
- [`copier`](#copier)
- [`Constructor` / `prototype`](#constructor--prototype)
- [`createStrictCopier`](#createstrictcopier)
- [Copier methods](#copier-methods)
- [Types supported](#types-supported)
Expand Down Expand Up @@ -98,6 +102,93 @@ const copyShallow = createCopier({
});
```

Each internal copier method has the following contract:

```ts
type InternalCopier<Value> = (value: Value, state: State) => Value;

interface State {
Constructor: any;
cache: WeakMap;
copier: InternalCopier<any>;
prototype: any;
}
```

Any method overriding the defaults must maintain this contract.

#### Copier state

##### `cache`

If you want to maintain circular reference handling, then you'll need the methods to handle cache population for future lookups:

```ts
function shallowlyCloneArray<Value extends any[]>(
value: Value,
state: State
): Value {
const clone = [...value];

state.cache.set(value, clone);

return clone;
}
```

##### `copier`

`copier` is provided for recursive calls with deeply-nested objects.

```ts
function deeplyCloneArray<Value extends any[]>(
value: Value,
state: State
): Value {
const clone = [];

state.cache.set(value, clone);

value.forEach((item) => state.copier(item, state));

return clone;
}
```

Note above I am using `forEach` instead of a simple `map`. This is because it is highly recommended to store the clone in [`cache`](#cache) eagerly when deeply copying, so that nested circular references are handled correctly.

##### `Constructor` / `prototype`

Both `Constructor` and `prototype` properties are only populated with complex objects that are not standard objects or arrays. This is mainly useful for custom subclasses of these globals, or maintaining custom prototypes of objects.

```ts
function deeplyCloneSubclassArray<Value extends CustomArray>(
value: Value,
state: State
): Value {
const clone = new state.Constructor();

state.cache.set(value, clone);

value.forEach((item) => clone.push(item));

return clone;
}

function deeplyCloneCustomObject<Value extends CustomObject>(
value: Value,
state: State
): Value {
const clone = Object.create(state.prototype);

state.cache.set(value, clone);

Object.entries(value).forEach(([k, v]) => (clone[k] = v));

return clone;
}
```

### `createStrictCopier`

Create a custom copier based on the type-specific methods passed, but defaulting to the same functions normally used for `copyStrict`. This is useful if you want to squeeze out better performance while maintaining strict requirements, or perform something other than a strict deep copy.
Expand Down
4 changes: 2 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ export interface CreateCopierOptions {
set?: InternalCopier<Set<any>>;
}

type InternalCopier<Value = any> = (value: Value, state: State) => Value;
type InternalCopier<Value> = (value: Value, state: State) => Value;

export interface State {
Constructor: any;
cache: Cache;
copier: InternalCopier;
copier: InternalCopier<any>;
prototype: any;
}

Expand Down
4 changes: 2 additions & 2 deletions src/copier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { getCleanClone, getRegExpFlags } from './utils';

import type { Cache } from './utils';

export type InternalCopier<Value = any> = (value: Value, state: State) => Value;
export type InternalCopier<Value> = (value: Value, state: State) => Value;

export interface State {
Constructor: any;
cache: Cache;
copier: InternalCopier;
copier: InternalCopier<any>;
prototype: any;
}

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const DEFAULT_STRICT_OPTIONS: Required<CreateCopierOptions> = assign(

function getTagSpecificCopiers(
options: Required<CreateCopierOptions>
): Record<string, InternalCopier> {
): Record<string, InternalCopier<any>> {
return {
Array: options.array,
ArrayBuffer: options.arrayBuffer,
Expand Down

0 comments on commit a4a8d67

Please sign in to comment.