Access deep object properties using a path
npx @tessl/cli install tessl/npm-object-path@0.11.0Object Path is a JavaScript utility library for accessing and manipulating deep object properties using string paths or arrays. It provides safe traversal of nested object structures with comprehensive functionality for getting, setting, deleting, and testing existence of deeply nested properties.
npm install object-pathconst objectPath = require("object-path");For ES modules:
import objectPath from "object-path";Browser global:
// Available as window.objectPathconst objectPath = require("object-path");
const obj = {
a: {
b: "value",
c: ["item1", "item2"],
"special.key": "data"
}
};
// Get deep property
objectPath.get(obj, "a.b"); // returns "value"
objectPath.get(obj, ["a", "special.key"]); // returns "data"
// Set deep property
objectPath.set(obj, "a.d", "new value");
objectPath.set(obj, "a.e.0", "array item"); // creates intermediate objects/arrays
// Check existence
objectPath.has(obj, "a.b"); // returns true
objectPath.has(obj, "a.missing"); // returns false
// Delete property
objectPath.del(obj, "a.b"); // removes the propertyObject Path is built around several key concepts:
Access and manipulate deep object properties using various path formats.
/**
* Gets a deep property value using a path
* @param {object} obj - The object to traverse
* @param {string|array|number} path - The path to the property
* @param {any} defaultValue - Value to return if path doesn't exist
* @returns {any} The value at the path or defaultValue
*/
objectPath.get(obj, path, defaultValue);
/**
* Sets a deep property value, creating intermediate objects/arrays as needed
* @param {object} obj - The object to modify
* @param {string|array|number} path - The path to set
* @param {any} value - The value to set
* @param {boolean} doNotReplace - If true, won't replace existing values
* @returns {any} The previous value at the path
*/
objectPath.set(obj, path, value, doNotReplace);
/**
* Tests whether a deep property exists
* @param {object} obj - The object to test
* @param {string|array|number} path - The path to test
* @returns {boolean} True if property exists
*/
objectPath.has(obj, path);
/**
* Deletes a deep property (splices arrays, deletes object properties)
* @param {object} obj - The object to modify
* @param {string|array|number} path - The path to delete
* @returns {object} The modified object
*/
objectPath.del(obj, path);Usage Examples:
const obj = { a: { b: { c: "value" } } };
// Different path formats
objectPath.get(obj, "a.b.c"); // "value"
objectPath.get(obj, ["a", "b", "c"]); // "value"
objectPath.get(obj, ["a.b", "c"]); // undefined (literal key "a.b")
// Default values
objectPath.get(obj, "missing.path", "default"); // "default"
// Setting with path creation
objectPath.set(obj, "x.y.z", "new"); // Creates nested structure
objectPath.set(obj, "arr.0", "first"); // Creates array at obj.arr
// Conditional setting (doNotReplace = true)
objectPath.set(obj, "a.b.c", "new", true); // Won't replace existing "value"
objectPath.set(obj, "x.y.z", "new", true); // Will set since path doesn't existSpecialized methods for working with arrays at specific paths.
/**
* Pushes values to an array at the given path, creating the array if needed
* @param {object} obj - The object to modify
* @param {string|array|number} path - The path to the array
* @param {...any} values - Values to push
*/
objectPath.push(obj, path, ...values);
/**
* Inserts a value into an array at a specific index
* @param {object} obj - The object to modify
* @param {string|array|number} path - The path to the array
* @param {any} value - The value to insert
* @param {number} at - The index to insert at (defaults to 0)
*/
objectPath.insert(obj, path, value, at);Usage Examples:
const obj = { items: ["a", "b"] };
// Push multiple values
objectPath.push(obj, "items", "c", "d"); // obj.items = ["a", "b", "c", "d"]
// Create array and push
objectPath.push(obj, "newArray", "first"); // obj.newArray = ["first"]
// Insert at specific position
objectPath.insert(obj, "items", "inserted", 1); // obj.items = ["a", "inserted", "b", "c", "d"]Advanced operations for data manipulation and retrieval.
/**
* Empties a property while maintaining object/array references
* @param {object} obj - The object to modify
* @param {string|array|number} path - The path to empty
* @returns {any} The previous value
*/
objectPath.empty(obj, path);
/**
* Sets a value only if the path doesn't already exist
* @param {object} obj - The object to modify
* @param {string|array|number} path - The path to ensure
* @param {any} value - The default value to set
* @returns {any} The existing or newly set value
*/
objectPath.ensureExists(obj, path, value);
/**
* Returns the first non-undefined value from multiple paths
* @param {object} obj - The object to search
* @param {array} paths - Array of paths to try
* @param {any} defaultValue - Value to return if all paths are undefined
* @returns {any} The first defined value or defaultValue
*/
objectPath.coalesce(obj, paths, defaultValue);Usage Examples:
const obj = {
data: { count: 5, items: ["a", "b"], active: true },
text: "hello"
};
// Empty different types while preserving references
objectPath.empty(obj, "text"); // obj.text = ""
objectPath.empty(obj, "data.count"); // obj.data.count = 0
objectPath.empty(obj, "data.active"); // obj.data.active = false
objectPath.empty(obj, "data.items"); // obj.data.items = [] (same array reference)
// Ensure existence
objectPath.ensureExists(obj, "config.timeout", 5000); // Sets only if missing
const existing = objectPath.ensureExists(obj, "text", "default"); // Returns ""
// Coalesce - find first existing value
const value = objectPath.coalesce(obj, [
"user.preferences.theme",
"defaults.theme",
"config.theme"
], "light"); // Returns "light" if none existCreate configured instances for different behaviors and security requirements.
/**
* Creates a new object-path instance with custom options
* @param {object} options - Configuration options
* @param {boolean} options.includeInheritedProps - Whether to access inherited properties
* @returns {object} New object-path instance with all methods
*/
objectPath.create(options);
/**
* Pre-configured instance that accesses inherited properties
* @type {object}
*/
objectPath.withInheritedProps;
/**
* Creates a bound instance with all methods pre-bound to the given object
* @param {object} obj - The object to bind to
* @returns {object} Bound instance with get, set, del, has, push, insert, empty, ensureExists, coalesce methods
*/
objectPath(obj);Usage Examples:
// Create instance with inherited properties support
const inheritedPath = objectPath.create({ includeInheritedProps: true });
// Use pre-configured inherited instance
const proto = { inherited: { value: "from prototype" } };
const obj = Object.create(proto);
objectPath.withInheritedProps.get(obj, "inherited.value"); // "from prototype"
// Create bound instance for cleaner repeated operations
const model = objectPath({
user: { name: "Alice", preferences: { theme: "dark" } }
});
model.get("user.name"); // "Alice"
model.set("user.age", 25); // Sets obj.user.age = 25
model.has("user.preferences.theme"); // true
model.del("user.preferences"); // Deletes the preferences objectObject Path includes built-in protection against prototype pollution attacks.
// Default mode - only accesses own properties (secure)
const obj = Object.create({ inherited: "value" });
objectPath.get(obj, "inherited"); // undefined (safe)
// Inherited props mode - includes security checks
const inheritedPath = objectPath.withInheritedProps;
// These will throw errors for security:
// inheritedPath.set(obj, "__proto__.polluted", true); // Error
// inheritedPath.set(obj, "constructor.prototype.polluted", true); // ErrorObject Path supports multiple path formats for maximum flexibility:
// String paths with dot notation
"property.nested.deep"
"array.0.property"
"unicode.ключ.property"
// Array paths (handles keys with dots)
["property", "nested", "deep"]
["array", 0, "property"]
["key.with.dots", "nested"]
// Numeric paths (converted to single-element array)
0 // equivalent to [0]
1 // equivalent to [1]// Path types
type Path = string | (string | number)[] | number;
// Instance interface (returned by objectPath.create())
interface ObjectPath {
get(obj: object, path: Path, defaultValue?: any): any;
set(obj: object, path: Path, value: any, doNotReplace?: boolean): any;
has(obj: object, path: Path): boolean;
del(obj: object, path: Path): object;
push(obj: object, path: Path, ...values: any[]): void;
insert(obj: object, path: Path, value: any, at?: number): void;
empty(obj: object, path: Path): any;
ensureExists(obj: object, path: Path, value: any): any;
coalesce(obj: object, paths: Path[], defaultValue?: any): any;
}
// Bound instance interface (returned by objectPath(obj))
interface BoundObjectPath {
get(path: Path, defaultValue?: any): any;
set(path: Path, value: any, doNotReplace?: boolean): any;
has(path: Path): boolean;
del(path: Path): object;
push(path: Path, ...values: any[]): void;
insert(path: Path, value: any, at?: number): void;
empty(path: Path): any;
ensureExists(path: Path, value: any): any;
coalesce(paths: Path[], defaultValue?: any): any;
}
// Configuration options
interface ObjectPathOptions {
includeInheritedProps?: boolean;
}