// We have some state like: const state1 = { data: { some: 'stuff' }, people: ['blah', 'blah', 'blah'], memberships: [ { id: 1, roles: [], other: 'stuff' }, { id: 2, roles: ['client'], more: 'junk' } ] }; // We want to be able to add a role to a particular membership (without mutation) (but without ramda): const addRole = (id, role) => (obj) => { const newMemberships = obj.memberships.map((membership) => { if (membership.id == id) { const newRoles = membership.roles.concat(role) return Object.assign({}, membership, {roles: newRoles}) } else { return membership } }) return Object.assign({}, obj, {memberships: newMemberships}) } // For example: addRole(2, 'admin')(state1) // …returns a new object, in which `data`, `people`, and membership id 1 are all the exact same objects as before (not copies): { data: { some: 'stuff' }, people: ['blah', 'blah', 'blah'], memberships: [ { id: 1, roles: [], other: 'stuff' }, { id: 2, roles: ['client', 'admin'], more: 'junk' } ] }