Skip to content

Instantly share code, notes, and snippets.

@amsterdamharu
Last active March 17, 2021 19:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amsterdamharu/659bb39912096e74ba1c8c676948d5d9 to your computer and use it in GitHub Desktop.
Save amsterdamharu/659bb39912096e74ba1c8c676948d5d9 to your computer and use it in GitHub Desktop.
const REMOVE = () => REMOVE;
const get = (object, path, defaultValue) => {
const recur = (current, path, defaultValue) => {
if (current === undefined) {
return defaultValue;
}
if (path.length === 0) {
return current;
}
return recur(
current[path[0]],
path.slice(1),
defaultValue
);
};
return recur(object, path, defaultValue);
};
const set = (object, path, callback) => {
const setKey = (current, key, value) => {
if (Array.isArray(current)) {
return value === REMOVE
? current.filter((_, i) => key !== i)
: current.map((c, i) => (i === key ? value : c));
}
return value === REMOVE
? Object.entries(current).reduce((result, [k, v]) => {
if (k !== key) {
result[k] = v;
}
return result;
}, {})
: { ...current, [key]: value };
};
const recur = (current, path, newValue) => {
if (path.length === 1) {
return setKey(current, path[0], newValue);
}
return setKey(
current,
path[0],
recur(current[path[0]], path.slice(1), newValue)
);
};
const oldValue = get(object, path);
const newValue = callback(oldValue);
if (oldValue === newValue) {
return object;
}
return recur(object, path, newValue);
};
const data = {
name: [{ hello: 'world', stay: true }, 4],
list: [1, 2, 3],
};
console.log(
'setting nested value',
set(data, ['name', 0, 'hello'], () => 'hello world')
.name[0].hello
);
console.log(
'doubling nested value',
set(data, ['name', 1], x => x * 2).name[1]
);
console.log(
'removing nested value',
set(data, ['name', 0, 'hello'], REMOVE).name[0]
);
console.log(
'adding to an array',
set(data, ['list'], v => [...v, 4]).list
);
console.log(
'mapping an array',
set(data, ['list'], v => v.map(v => v * 8)).list
);
console.log(
'return same reference if nothing changed',
set(data, ['list'], x => x) === data
);
console.log(
'data is not mutated',
JSON.stringify(data, undefined, 2)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment