Skip to content

Latest commit

 

History

History

paths

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

@thi.ng/paths

npm (scoped)

This project is part of the @thi.ng/umbrella monorepo.

About

This library provides immutable, optimized path-based accessors for vanilla JS objects.

Installation

yarn add @thi.ng/paths

Usage

import * as paths from "@thi.ng/paths";

The getter() and setter() functions transform a path like a.b.c into a function operating directly at the value the path points to in nested object. For getters, this essentially compiles to val = obj.a.b.c, with the important difference that the function returns undefined if any intermediate values along the lookup path are undefined (and doesn't throw an error).

The resulting setter function too accepts a single object to operate on and when called, immutably replaces the value at the given path, i.e. it produces a selective deep copy of obj up until given path. If any intermediate key is not present in the given object, it creates a plain empty object for that missing key and descends further along the path.

s = setter("a.b.c");
// or
s = setter(["a","b","c"]);

s({a: {b: {c: 23}}}, 24)
// {a: {b: {c: 24}}}

s({x: 23}, 24)
// { x: 23, a: { b: { c: 24 } } }

s(null, 24)
// { a: { b: { c: 24 } } }

In addition to these higher-order functions, the module also provides immediate-use wrappers: getIn(), setIn(), updateIn() and deleteIn(). These functions are using getter / setter internally, so have same behaviors.

state = {a: {b: {c: 23}}};

getIn(state, "a.b.c")
// 23

setIn(state, "a.b.c", 24)
// {a: {b: {c: 24}}}

// apply given function to path value
updateIn(state, "a.b.c", x => x + 1)
// {a: {b: {c: 24}}}

// immutably remove path key
deleteIn(state, "a.b.c.")
// {a: {b: {}}}

Only keys in the path will be updated, all other keys present in the given object retain their original/identical values to provide efficient structural sharing / re-use. This is the same behavior as in Clojure's immutable maps or those provided by ImmutableJS (albeit those implementation are completely different - they're using trees, we're using the ES6 spread op and recursive functional composition to produce the setter/updater).

s = setter("a.b.c");

// original
a = { x: { y: { z: 1 } }, u: { v: 2 } };
// updated version
b = s(a, 3);
// { x: { y: { z: 1 } }, u: { v: 2 }, a: { b: { c: 3 } } }

// verify anything under keys `x` & `u` is still identical
a.x === b.x // true
a.x.y === b.x.y // true
a.u === b.u; // true

Authors

  • Karsten Schmidt

License

© 2016 - 2018 Karsten Schmidt // Apache Software License 2.0