Skip to content

Instantly share code, notes, and snippets.

@rbinksy
Last active July 18, 2021 09:24
Show Gist options
  • Save rbinksy/448b176b0b4fe25cc2da0925215a27da to your computer and use it in GitHub Desktop.
Save rbinksy/448b176b0b4fe25cc2da0925215a27da to your computer and use it in GitHub Desktop.
Updating nested objects in Typescript
import { Lens } from 'monocle-ts';
import { id, prop, modify } from 'monocle-ts/Lens';
import { pipe } from 'fp-ts/function';
import { merge, set, cloneDeep } from 'lodash/fp';
import produce from 'immer';
interface Street {
num: number;
name: string;
}
interface Address {
city: string;
street: Street;
}
interface Company {
name: string;
address: Address;
}
interface Employee {
name: string;
company: Company;
}
const employee: Employee = {
name: 'john',
company: {
name: 'awesome inc',
address: {
city: 'london',
street: {
num: 23,
name: 'high street',
},
},
},
};
it('should update a nested value in an object', () => {
/**
* Object spread
*/
const employeeEditedNative: Employee = {
...employee,
company: {
...employee.company,
address: {
...employee.company.address,
street: {
...employee.company.address.street,
name: 'Updated Road',
},
},
},
};
/**
* Lodash deep merge (current)
*/
const employeeEditedLodashMerge: Employee = merge(employee, {
company: {
address: {
street: {
name: 'Updated Road',
},
},
},
});
/**
* Lodash set
*/
const employeeEditedLodashSet: Employee = set(
'company.address.street.name',
'Updated Road'
)(employee);
/**
* Lodash deep clone and mutate
*/
const employeeEditedMutated: Employee = cloneDeep(employee);
employeeEditedMutated.company.address.street.name = 'Updated Road';
/**
* Immer
*/
const employeeEditedImmer: Employee = produce(employee, (draft) => {
draft.company.address.street.name = 'Updated Road';
});
/**
* Monacle
*/
const nameLens = Lens.fromPath<Employee>()([
'company',
'address',
'street',
'name',
]);
const employeeEditedMonacle = nameLens.modify(() => 'Updated Road')(employee);
/**
* Monacle Experimental API
*/
const nameLensV2 = pipe(
id<Employee>(),
prop('company'),
prop('address'),
prop('street'),
prop('name')
);
const employeeEditedMonacleV2 = pipe(
nameLensV2,
modify(() => 'Updated Road')
)(employee);
expect(employeeEditedLodashMerge).toStrictEqual(employeeEditedNative);
expect(employeeEditedLodashSet).toStrictEqual(employeeEditedNative);
expect(employeeEditedImmer).toStrictEqual(employeeEditedNative);
expect(employeeEditedMutated).toStrictEqual(employeeEditedNative);
expect(employeeEditedMonacle).toStrictEqual(employeeEditedNative);
expect(employeeEditedMonacleV2).toStrictEqual(employeeEditedNative);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment