UNPKG

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
// # 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 };