Skip to the code
cf.

Get by path

Write get(object, path, defaultValue). It walks down object along path and returns the value it finds there.

path is either a string of keys separated by dots, with array indexes in brackets ("a.b[0].c"), or an array of keys (["a", "b", 0, "c"]). Keys in an array are used as they are, even if they contain dots.

Return defaultValue when a step along the way is null or undefined, or when the value you find is undefined; a missing step never throws. A stored null, 0, "", or false is a real value, so return it as it is. Primitives along the way work like objects: "name.length" reads a string's length.

const user = { name: "Ada", posts: [{ title: "Hi", tags: ["js"] }] };
 
get(user, "posts[0].tags[0]");      // "js"
get(user, ["posts", 0, "title"]);   // "Hi"
get(user, "posts[1].title", "n/a"); // "n/a"
get(user, "name.length");           // 3

What the tests check

  1. reads a nested value with a dotted path
    expect(get({ a: { b: { c: 1 } } }, "a.b.c")).toBe(1);
    
  2. reads array indexes in brackets
    expect(get({ a: { b: [{ c: 3 }] } }, "a.b[0].c")).toBe(3);
    expect(get({ m: [[1, 2], [3, 4]] }, "m[1][0]")).toBe(3);
    
  3. accepts an array of keys, used as they are
    expect(get({ a: { b: [{ c: 3 }] } }, ["a", "b", 0, "c"])).toBe(3);
    expect(get({ "x.y": 1 }, ["x.y"])).toBe(1);
    
  4. returns the default when a step is missing
    expect(get({ a: null }, "a.b.c", "none")).toBe("none");
    expect(get({}, "x.y.z", 5)).toBe(5);
    expect(get({ list: [] }, "list[2].name", "n/a")).toBe("n/a");
    
  5. returns the default when the value is undefined
    expect(get({ a: { b: undefined } }, "a.b", "default")).toBe("default");
    
  6. returns stored falsy values as they are
    expect(get({ a: { b: 0 } }, "a.b", 5)).toBe(0);
    expect(get({ a: { b: null } }, "a.b", 5)).toBeNull();
    expect(get({ a: { b: "" } }, "a.b", 5)).toBe("");
    expect(get({ a: { b: false } }, "a.b", 5)).toBe(false);
    
  7. reads properties of primitives along the way
    expect(get({ name: "Ada" }, "name.length")).toBe(3);
    
  8. returns undefined when there's no default
    expect(get({ a: 1 }, "b.c")).toBeUndefined();
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).