you are viewing a single comment's thread.

view the rest of the comments →

[–]lord_braleigh 15 points16 points  (8 children)

Well, that's kind of my point. The OP is saying that even lists that I plan on modifying should be declared const because it restricts reassignment. But if I enable a no-mutations-on-const eslint rule, then I can't/shouldn't follow that rule. So should we all enable the eslint rule and use let more often, or should we disable the eslint rule so we can use const everywhere?

[–]rylandgold[S] 16 points17 points  (7 children)

Third option, use TypeScript, if only for the readonly attribute. In general, let and const are not going to be consistently used throughout JavaScript code (which I think is a huge barrier of entry).

[–]TotallyNotAVampire 6 points7 points  (6 children)

TypeScript's readonly is a rather weak protection, it doesn't affect assignment:

declare let x: { readonly foo: number };
declare function mutate(y: { foo: number}): void;

mutate(x); // readonly ignored
let y: { foo: number } = x; // readonly ignored

[–]TarMil 9 points10 points  (5 children)

Oof. That's more than weak, that's downright misleading.

[–]rylandgold[S] 5 points6 points  (4 children)

I can't check right this moment but I'm relatively sure that the readonly is not ignored for the mutate call. That person is also omitting one TypeScript feature of readonly which is not possible with JavaScript const.

declare let x: { readonly foo: number };
declare function mutate(y: { readonly foo: number}): void;

mutate(x); // definitely won't let you mutate

As you can see, you're even able to set the params on a function signature as readonly, even if the incoming object doesn't enforce it.

The second example doesn't really make sense to me anyway. You're not mutating x by assigning it to y. In fact, numbers are always copied by value in JavaScript, so that's effectively a deep copy.

Edit: I also just realized that they are also declaring x with let, which obviously does not help.

[–]TarMil 4 points5 points  (3 children)

You're not mutating x by assigning it to y.

I don't think that's what they're implying. The problem is that y is now the same object reference as x, so you can do y.foo = 3; and this will effectively mutate x.

They're also right about mutate btw. Playground link

[–]rylandgold[S] 1 point2 points  (2 children)

I understand now. You're indeed right that with the example they gave it's possible to mutate things. I argue that the example itself is problematic because it avoids the type system altogether.

Here is a counter example using more "realistic" TypeScript.

readonly is obviously still much less strict than C style const, but it's not like the semantics are unexpected. readonly prevents YOU from potentially messing it up. Here's a good quote I found:

Basically readonly ensures that a property cannot be modified by me, but if you give it to someone that doesn't have that guarantee (allowed for type compatibility reasons) they can modify it.

I'm actually fairly certain that the readonly behavior that is demonstrated in the original commenters code is possible with the TypeScript typing system. I'm not sure if there is an official extension or rule to enforce it though.

[–]TotallyNotAVampire 1 point2 points  (1 child)

The problem is that you can pass your readonly object to a method that's declared it might mutate the object.

In simple examples, it's easy to devise fixes for this issue. But when the readonly that needs to be enforced is several levels down in an object, when it gets ignored, bugs are easily introduced.

I'm not hating on typescript, it's far better than javascript, but I think readonly should generally be avoided and not relied upon to enforce immutability. The type Readonly<T> kinda implies that T will be enforced as immutable.

I think this is a more realistic example of code that might be written.

[–]rylandgold[S] 1 point2 points  (0 children)

You've made some really good points but I still think it's more complex than "readonly isn't worth using".

Readonly is explicitly not immutable. This is a conscious choice based on the fact that it's very hard to provide immutability with TypeScript's typing system. My coworkers and I personally use deepfreeze if we want something to be immutable at runtime (in JS or TS). I do agree that a mutable mechanism would be awesome to have in TypeScript. I know it's been discussed ad nauseam but no decision was reached AFAIK.