Skip to content

Helpers ​

Generic object and path helpers — the small building blocks the hooks and utilities in this package are made of: reading, writing and picking dot paths, deep equality, and a few type checks. They cover what a Feathers app usually pulls in lodash for, with semantics tuned for Feathers: writes never leak into a caller's params, and comparisons understand symbol operators and ObjectIds.

ts
import { getPath, setPath, pickPaths, isEqual } from 'feathers-utils/helpers'
UtilityDescription
getPath

Reads the value at path, returning defaultValue when the path does not resolve or resolves to undefined. Descending stops at null/undefined instead of throwing.

A path is a dot/bracket string ('user.id', 'list[0].x') or an array of segments (['user', 'id']).

hasPath

Whether path resolves to an own property — inherited properties do not count, so a key named toString is only reported when the object really carries it. A property that exists but holds undefined counts.

isEmptyObject

Returns true only for a plain object without keys ({}). Arrays, null, undefined, primitives, class instances (a Date has no own keys either) and non-empty objects are all false - an object with only symbol keys (sequelize's operators) included.

isEqual

Deep equality for the values a Feathers app passes around — data, results, queries and params. Plain objects are compared by their own enumerable keys in any order (symbols included - sequelize uses them as operators), arrays by their elements, dates and regular expressions by value, a mongo ObjectId (anything with toHexString) by its hex string, and everything else - functions, class instances, maps, sets - by reference: a class instance may keep its state in private fields, so equal looking instances aren't necessarily equal. Self-references are fine.

It never mistakes different values for equal, but may miss equal ones (two distinct Maps with the same entries).

isPlainObject

Type guard for a plain object — one whose prototype is Object.prototype or null. Arrays, null, primitives and class instances (Date, RegExp, Map, bson ObjectId, ...) are all false.

isPromise

Type guard that checks if a value is a native Promise instance. A thenable that is not a Promise is false.

omitPaths

Returns a copy of object without the given paths. Paths may be nested ('user.email'), in which case the objects on the way are copied so the source keeps its key; untouched branches stay shared by reference. Arrays and class instances on the path are copied too — nothing here writes into what it was handed.

Each entry of paths is one path, and a segment array is one nested path — the same reading as in getPath/hasPath/setPath.

pickPaths

Returns an object holding only the given paths of object. Paths may be nested ('user.email'), in which case the result is nested the same way. Paths that do not resolve are skipped; the source is never written to.

Each entry of paths is one path, and a segment array is one nested path — the same reading as in getPath/hasPath/setPath.

setPath

Writes value at path, copying every object on the way — the copy-on-write that leaves a caller's params untouched.

target itself IS mutated (a hook owns context and re-assigns context.params); everything below it is replaced by a shallow copy, so untouched branches keep their identity. That matters for values Feathers compares by reference, such as params.connection, which a deep clone would break.

Missing segments are created as an array when the next key is an integer index, otherwise as a plain object. Paths through __proto__, constructor or prototype are ignored.

toArray

Normalizes a value or array into an array. The returned array MUST be treated as read-only — when the input is already an array it is returned as-is (no copy) to avoid a per-call allocation on hook hot paths.

Released under the MIT License.