Issue
As per the const assertion
in TS:
Another thing to keep in mind is that const contexts don’t immediately convert an expression to be fully immutable.
I couldn't understand how TS is not able to make it immutable. Ideally it should throw error.
let arr = [1, 2, 3, 4];
let foo = {
name: "foo",
contents: arr,
} as const;
foo.name = "bar"; // error!
foo.contents = []; // error!
foo.contents.push(5); // ...works!
If we add array value inside the foo
object as literal then it is working:
let foo = {
name: "foo",
contents: [1, 2, 3, 4],
} as const;
foo.name = "bar"; // error!
foo.contents = []; // error!
foo.contents.push(5); // NOW THROW ERROR
How come this is working and what exactly does don’t immediately convert and expression
mean?
Solution
The "immutability" applied by TypeScript is shallow and type-level. It doesn't enforce deep immutability, nor does it change the runtime JavaScript behavior. TypeScript's type system is designed to provide compile-time type checking and does not impact runtime behavior.
In your first example, foo.name
becomes readonly because it's a direct property of foo
. foo.contents
is also readonly, preventing you from reassigning it to a different array. However, the contents of arr
(and by extension foo.contents
since it references arr
) are not made deeply immutable by the const assertion. This means you can still modify arr
(and thus foo.contents
) by pushing elements into it or changing its elements if they were objects.
In your second example, foo
and its properties are treated similarly at the top level. name is readonly, and contents cannot be reassigned. The difference arises because you've directly placed the array literal inside foo
. When you do this, TypeScript infers the type of contents as a readonly tuple (readonly [1, 2, 3, 4]
), which makes each element of the array also readonly. It might look like deep immutability, but it's actually the result of how TypeScript treats literals in a const context—it makes the elements of the array literal immutable because it treats them as a tuple.
You can make the first example throw as well, by just making the initial arr
a const
as well:
let arr = [1, 2, 3, 4] as const;
let foo = {
name: "foo",
contents: arr,
} as const;
foo.name = "bar"; // error!
foo.contents = []; // error!
foo.contents.push(5); // error!
Answered By - Titulum
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.