reflect-deep
Version:
Deep property manipulation utilities with robust cloning, path traversal, and property access for JavaScript/TypeScript objects.
201 lines (199 loc) • 9.06 kB
TypeScript
// # index.d.ts
interface ReachResult {
/**
* The furthest reachable value in the object at the given property path.
*/
value: any;
/**
* The index in `propertyKeys` of the last successfully accessed property.
* - Will be -1 if the first property failed.
*/
index: number;
/**
* Whether the path was fully traversed and the final value was successfully reached.
*/
reached: boolean;
}
interface GroupedKey {
/**
* Keys (includes symbols)
*/
keys: (string | symbol)[];
/**
* Target itself or its prototype.
*/
object: any;
}
/**
* ## Usage
* Just type ReflectDeep and add `.` to it to access its methods
*
* ## About
* @package ReflectDeep
* @author KasukabeTsumugi <futami16237@gmail.com>
* @version 1.3.3 (Last Update: 2025.08.15 01:39:53.878)
* @license MIT
* @link https://github.com/baendlorel/reflect-deep
* @description Deep property manipulation utilities with robust cloning, path traversal, and property access for JavaScript/TypeScript objects.
* @copyright Copyright (c) 2025 KasukabeTsumugi. All rights reserved.
*/
declare class ReflectDeep extends null {
constructor();
/**
* Checks if a nested property exists at the given path.
* @param target - Target object to check.
* @param propertyKeys - Property path to check.
* @returns `true` if the property exists, `false` otherwise.
* @throws If target is not an object or propertyKeys is invalid.
* @throws If target is not an object or propertyKeys is not a valid non-empty array.
* @example
* const obj = { a: { b: { c: 'hello' } } };
* ReflectDeep.has(obj, ['a', 'b', 'c']); // true
*/
static has(target: object, propertyKeys: PropertyKey[]): boolean;
/**
* Gets the value of a nested property.
* @param target - Target object.
* @param propertyKeys - Property path.
* @param receiver - The `this` value for getter calls.
* @returns The property value, or `undefined` if not found.
* @throws If target is not an object or propertyKeys is invalid.
* @throws If target is not an object or propertyKeys is not a valid non-empty array.
* @example
* const obj = { a: { b: { c: 'hello' } } };
* ReflectDeep.get(obj, ['a', 'b', 'c']); // 'hello'
*/
static get<T = any>(target: any, propertyKeys: PropertyKey[], receiver?: any): T | undefined;
/**
* Sets a nested property value, creating intermediate objects as needed.
* @param target - Target object.
* @param propertyKeys - Property path.
* @param value - Value to set.
* @param receiver - The `this` value for setter calls.
* @returns `true` if successful, `false` otherwise.
* @throws If target is not an object or propertyKeys is invalid.
* @throws If target is not an object or propertyKeys is not a valid non-empty array.
* @example
* const obj = { };
* ReflectDeep.set(obj, ['a', 'b', 'c'], 'hello'); // Creates nested structure
* obj.a.b.c; // 'hello'
*/
static set<T = any>(target: any, propertyKeys: PropertyKey[], value: T, receiver?: any): boolean;
/**
* Traverses a property path and returns the furthest reachable value with its index.
* @param target - Target object to traverse.
* @param propertyKeys - Property path to traverse.
* @param receiver - The `this` value for getter calls.
* @returns Object with `value` (furthest reachable value), `index` (position reached), and `reached` (whether the full path was traversed).
* @throws If target is not an object or propertyKeys is invalid.
* @throws If target is not an object or propertyKeys is not a valid non-empty array.
* @example
* const obj = { a: { b: { c: 'hello' } } };
* ReflectDeep.reach(obj, ['a', 'b', 'c']); // { value: 'hello', index: 2, reached: true }
* ReflectDeep.reach(obj, ['a', 'b', 'd']); // { value: { c: 'hello' }, index: 1, reached: false }
* ReflectDeep.reach(obj, ['a', 'x']); // { value: { b: { c: 'hello' } }, index: 0, reached: false }
* ReflectDeep.reach(obj, ['d', 'x']); // { value: { a: { b: { c: 'hello' } } }, index: -1, reached: false }
*/
static reach(target: object, propertyKeys: PropertyKey[], receiver?: any): ReachResult;
/**
* Creates a deep clone of an object, handling circular references and various JS types.
*
* **Circular references are fully suppported**
*
* ! Will not check depth of the object, so be careful with very deep objects.
* @param obj - Object to clone.
* @returns A deep clone of the object.
* @example
* const obj = { a: { b: [1, 2, { c: 3 }] } };
* const cloned = ReflectDeep.clone(obj);
* cloned.a.b[2].c = 4; // obj.a.b[2].c is still 3
*/
static clone<T = any>(obj: T): T;
/**
* Deletes a nested property at the given path.
*
* **Has same behavior as the original `Reflect.deleteProperty`**
* - property does not exist, return `true`
* - exists and configurable, return `true`
* - exists but not configurable, return `false`
* - `target` is frozen, return `false`
* @param target Target object.
* @param propertyKeys Property path to delete.
* @returns `true` if successful, `false` otherwise.
* @throws If target is not an object or propertyKeys is not a valid non-empty array.
* @example
* const obj = { a: { b: { c: 'hello', d: 'world' } } };
* ReflectDeep.deleteProperty(obj, ['a', 'b', 'c']); // true
* obj.a.b; // { d: 'world' }
*/
static deleteProperty(target: object, propertyKeys: PropertyKey[]): boolean;
/**
* Defines a nested property with the given descriptor, creating intermediate objects as needed.
*
* **Has same behavior as the original `Reflect.defineProperty`**
* @param target Target object.
* @param propertyKeys Property path to define.
* @param descriptor Property descriptor to apply.
* @returns `true` if successful, `false` otherwise.
* @throws If target is not an object or propertyKeys is not a valid non-empty array.
* @example
* const obj = {};
* ReflectDeep.defineProperty(obj, ['a', 'b', 'c'], { value: 'hello', writable: true });
* obj.a.b.c; // 'hello'
*
* // Define getter/setter
* ReflectDeep.defineProperty(obj, ['x', 'y'], {
* get() { return this._value; },
* set(v) { this._value = v; }
* });
*/
static defineProperty(target: object, propertyKeys: PropertyKey[], descriptor: PropertyDescriptor): boolean;
/**
* Gets all property keys (including symbols) from the target object and its prototype chain.
* Returns a flattened array of unique keys from all prototype layers.
* @param target - Target object to extract keys from.
* @returns Array of all unique property keys from the object and its prototype chain.
* @throws If target is not an object.
* @throws If target is not an object.
* @example
* const obj = { own: 'property', [Symbol('sym')]: 'symbol' };
* const keys = ReflectDeep.keys(obj);
* // Returns: ['own', Symbol(sym), 'toString', 'valueOf', ...] (includes prototype keys)
*
* // Works with custom prototypes
* function Parent() {}
* Parent.prototype.parentProp = 'parent';
* const child = Object.create(Parent.prototype);
* child.childProp = 'child';
* ReflectDeep.keys(child); // ['childProp', 'parentProp', 'toString', ...]
*/
static keys<T extends object>(target: T): (string | symbol)[];
/**
* Gets property keys grouped by prototype layer, preserving the prototype chain structure.
* Returns an array where each element represents a layer in the prototype chain with its keys and object reference.
* @param target - Target object to extract grouped keys from.
* @returns Array of objects, each containing `keys` and `object` for each prototype layer.
* @throws If target is not an object.
* @throws If target is not an object.
* @example
* const obj = { own: 'property', [Symbol('sym')]: 'symbol' };
* const grouped = ReflectDeep.groupedKeys(obj);
* // Returns: [
* // { keys: ['own', Symbol(sym)], object: obj },
* // { keys: ['toString', 'valueOf', ...], object: Object.prototype },
* // { keys: [], object: null }
* // ]
*
* // Useful for inspecting prototype chain structure
* function Parent() {}
* Parent.prototype.parentProp = 'parent';
* const child = Object.create(Parent.prototype);
* child.childProp = 'child';
* const layers = ReflectDeep.groupedKeys(child);
* // layers[0] = { keys: ['childProp'], object: child }
* // layers[1] = { keys: ['parentProp'], object: Parent.prototype }
* // layers[2] = { keys: ['toString', ...], object: Object.prototype }
*/
static groupedKeys<T extends object>(target: T): GroupedKey[];
}
export { ReflectDeep };