function copyWith (obj, key, value) { const result = typeof key === 'number' ? [...obj] : {...obj}; result[key] = value; return result; } export const cowValueModel = (...keyDescriptions) => { const keys = []; keyDescriptions.forEach(each => { if (typeof each === 'number') keys.push(each); else keys.push(...each.toString().split('.')); }); function setField (x = {}, index, val) { if (index >= keys.length) return val; const key = keys[index], value = x[key], modified = setField(value, index + 1, val); return value === modified ? x : copyWith(x, key, modified); } const GET_SENTINEL = {}; return (obj, val = GET_SENTINEL) => val === GET_SENTINEL ? keys.reduce((x = {}, key) => x[key], obj) : setField(obj, 0, val); };