For more tips like this, sign up to the weekly newsletter!
Conditionally set an immutable value
Setting an element in a mutable collection does permanent changes, conditionals are therefore easy to do:
let array = [1, 2];
if (condition1) {
array[0] = 5;
}
if (condition2) {
array[1] = 6;
}
After this code is run, array
is [1, 2]
, [5, 2]
, [1, 6]
, or [5, 6]
, depending on the two conditions.
But with an immutable collection, variable reassigning is needed to achieve the same effect:
let array = Immutable.List.of(1, 2);
if (condition1) {
array = array.set(0, 5);
}
if (condition2) {
array = array.set(1, 6);
}
While this works, it looks wrong and defeats the purpose of immutability.
Use IIFEs
To remedy this, use IIFEs and store each modification in a new constant:
const array = Immutable.List.of(1, 2);
const firstElementSetted = (() => {
return condition1 ? array.set(0, 5) : array;
})();
const secondElementSetted = (() => {
return condition2 ? firstElementSetted.set(1, 6) : firstElementSetted;
})();
It is a lot more code, but this approach nicely separates the steps and keeps both the variables and the collection immutable.
Refactoring to normal functions also promote reusability:
const conditionallySetFirstElement = (array, condition) => {
return condition ? array.set(0, 5) : array;
}
const conditionallySetSecondElement = (array, condition) => {
return condition ? array.set(1, 6) : array;
}
const array = Immutable.List.of(1, 2);
conditionallySetSecondElement(
conditionallySetFirstElement(
array, condition1
), condition2
);
Or if you are a fan of functional composition, that ugly pyramid at the end can also be flattened:
const conditionallySetFirstElement = (condition) => (array) => {
return condition ? array.set(0, 5) : array;
}
const conditionallySetSecondElement = (condition) => (array) => {
return condition ? array.set(1, 6) : array;
}
// or use lodash.flow or a similar library
const flow = (...funcs) => (val) => {
return funcs.reduce((v, f) => f(v), val);
}
const array = Immutable.List.of(1, 2);
flow(
conditionallySetFirstElement(condition1),
conditionallySetSecondElement(condition2)
)(array);