Table of Contents:
Introduction
Why const isn't always constant in JavaScript and TypeScript
How this relates to state managers
How this impacts React
How to make an object immutable
Conclusion
Introduction
When we declare a variable with the const
keyword in JavaScript and TypeScript, we expect it to be immutable, meaning that its value cannot be changed. This is generally true for simple values like numbers, booleans, and strings. However, when it comes to objects and arrays, things get a little more complicated.
Why const isn't always constant in JavaScript and TypeScript
In JavaScript and TypeScript, objects and arrays are stored by reference, not by value. This means that when you declare a constant object or array, you are actually declaring a constant reference to that object or array. This means that you cannot reassign the variable to a different object or array, but you can still mutate the object or array itself.
const person = { name: "Mohamed" };
// This will throw an error:
// Assignment to constant variable.
person = { name: "John" };
// This is perfectly fine:
person.name = "John";
In the first example, we are trying to reassign the person
variable to a different object. This will throw an error because person
is a constant variable.
In the second example, we are mutating the person
object by changing the value of the name
property. This is perfectly fine because we are not reassigning the person
variable itself.
diagram example:
How this relates to state managers:
When we use a state manager like Redux or MobX, we are typically storing our state as objects. This means that the same principles that apply to constant object values also apply to constant state values.
For example, if we have a constant state value called person
, we can still mutate the person
object by changing the value of the name
property. However, if we try to reassign the person
state value to a different object, our state manager will not update the state.
How this impacts React:
When we use the useState
hook in React, we are returning a constant object value. This means that the same principles that apply to constant object values also apply to constant state values in React.
For example, if we have a constant state value called person
, we can still mutate the person
object by changing the value of the name
property. However, if we try to reassign the person
state value to a different object, our React component will not re-render.
How to make an object immutable
If you want to make an object immutable, you can use the Object.freeze()
method. This will prevent any changes to the object's properties, including nested objects.
Here is an example:
let someObj = {};
someObj.prop = 1; // setting prop to '1'
Object.freeze(someObj); // after this line you can't modify object
someObj.prop = "changed"; // prop will remain '1'
console.log(someObj); // { prop: 1 }
Note: Object.freeze()
is a shallow freeze, meaning that nested objects can still be modified. To make nested objects immutable, you can use recursion.
Here is an example of a recursive function to freeze an object completely:
function completeFreeze(obj) {
Object.freeze(obj);
for (let key in obj) {
if (typeof obj[key] === "object") {
completeFreeze(obj[key]);
}
}
}
To use this function, simply pass the object that you want to freeze to it. For example:
const obj = {
upper: "something",
nested: {
nestProp: "this is nest prop",
},
};
completeFreeze(obj);
obj.nested.upper = "new"; // will not be changed
console.log(obj); // { upper: 'something', nested: { nestProp: 'this is nest prop' } }
Conclusion:
In conclusion, it is important to be aware that const
is not always constant in JavaScript and TypeScript. When it comes to objects and arrays, const
only prevents you from reassigning the variable to a different object or array. You can still mutate the object or array itself.
When using state managers and React, it is important to keep this in mind because it can impact how your state is updated and your components are re-rendered.
Additionally, you can use the Object.freeze()
method to make an object immutable. This will prevent any changes to the object's properties, including nested objects. You can also use a recursive function to freeze an object completely.
I hope this blog article has been helpful in explaining why const
isn't always constant in JavaScript and TypeScript, and how to avoid the common pitfalls.
Let's connect: