0

I'm having problems with TSlint and understanding why the for(i=0; ...) loop is not longer permitted.

Let's assume I have a simple code like:

this.filters['1','2','3'....];
for (let i = 0; i < this.filters.length; i++) {
      if (this.filters[i] === '2') {
        this.filters = new_value;
      }
    }

which TSlint is asking me to convert it to for-of. However, using for-of is not going to work as I need to modify the value and the for-of does not allow to modify. I could use something like

for (const [i, el] of this.filters.entries()) { 

but then I get a compilation warning TypeScript and Iterator: Type 'IterableIterator<T>' is not an array type and I do have to change the compilation options. Also, I could iterate over the keys() which I see a bit stupid having the for(const i=0...)

Can someone explain me why TSlint is still complaining about this and why is not allowing to use the for(const i=0; ....)

Furthermore, I just saw that if do this code in a for-of

this.filters['1','2','3'....];
for (let f of this.filters) {
      if (f === '2') {
        f = new_value;
      }
    }

I would end up with the same array as it is not modified after the loop, but however, if I have a similar approach but with objects

let filters = [{id:'1'},{id:'2'},{id:'3'}];
console.log(filters)
for (let f of filters) {
      if (f.id === '2') {
        f.id = 'toto';
      }
    }
console.log(filters)

Surprise, my array of objects is modified after the loop! Can someone explain me why ?

Thank you

I searched for the error and I saw it in github as an issue that was closed but I can't find the solution https://github.com/palantir/tslint/pull/1813

Alex Vovchuk
  • 2,828
  • 4
  • 19
  • 40
Javier
  • 117
  • 1
  • 11
  • `this.filters['1','2','3'....];` do you mean `this.filters = ['1','2','3'....];`? – VLAZ Sep 12 '19 at 13:26
  • Also, why do you want the index of the item? It seems that all you care about is each item's value, so a `for-of` seems appropriate. – VLAZ Sep 12 '19 at 13:27
  • Also weird to want to use const in the loop for the iterators – mplungjan Sep 12 '19 at 13:28
  • have you read https://palantir.github.io/tslint/rules/prefer-for-of/ also it's probably just your config rules that highlight it – Krzysztof Krzeszewski Sep 12 '19 at 13:28
  • The latter half of the question is unrelated to the first one - you are probably better off posting it as a separate one. – VLAZ Sep 12 '19 at 13:29
  • 1
    If any value in the array is `2`, you want to replace the whole array, but continue iterating at the same index? That seems strange. – crashmstr Sep 12 '19 at 13:31
  • 1
    Modifying the array while iterating is a bad idea, many bugs can creep in as you modify the code. What you are actually doing doesn't seem to make sense, reassign the entire array being iterated? Anyone else that has to modify that code will hate your for writing it that way ;) Suggestion, create a new array and modify/add new items to that. – Ruan Mendes Sep 12 '19 at 13:33
  • Also, you are conflating questions. Are you asking about `for of` or why do you have different behavior with variables that point to primitives or objects? You should probably create separate questions that are more digestable. That makes your questions easier to answer and more helpful to others who may have the same question. For the sentence that actually has a question mark, here's the answer https://stackoverflow.com/a/6605700/227299 – Ruan Mendes Sep 12 '19 at 13:38
  • I'm suggesting we close this as a dupe, if you have a question about the `for of`tslint rule, please ask another question focusing on that, not on the reference/value aspect that you seem to be unsure about – Ruan Mendes Sep 12 '19 at 13:43
  • It was just a way to put the code fast. Yes, it was a typo this.filters = ['1','2','3'....]. What I want to say is if I want to modify only one value of the array, how the hell I do it using for-of. Omg, you care more about that the two questions are unrelated than actually answering them... – Javier Sep 12 '19 at 13:50
  • @Javier yes, we do. This is what makes SO the site where people go for answers, because each question has focus. If you conflate two questions, then the answers will be of lower quality because they won't be addressing everything. – VLAZ Sep 12 '19 at 14:15

1 Answers1

1

With strings you get following:

String is assigned to f. Then new value is reassigned to f: f === '2'. But string from array is not touched.

With objects:

Reference to object is assigned to f. Then object is being modified: f.id = 'toto'. Since array contains only reference to an object - we get modified object in array.

Basically the answer ends up with difference between reference type and value type variables.

In your case if for (const [i, el] of this.filters.entries()) { does not work because of ts settings, you could try:

arr.forEach((entry, index) => arr[index] = ...);

or something more ugly:

for(entry of arr) {
    arr[arr.indexOf(entry)] = ...;
}
Alex Vovchuk
  • 2,828
  • 4
  • 19
  • 40
  • I think this is potentially what the OP is asking, but their question is confusing and so is this answer. A runnable example would help clarify. You can explain that in the loop, if you reassign a variable that points to a primitive, you're not going to modify what's in the array. Having said that, if this is what they are asking, this has been asked a thousand times before and should closed as a duplicate https://stackoverflow.com/a/6605700/227299 – Ruan Mendes Sep 12 '19 at 13:37
  • Thank you Mendes, but actually Alex helped way more than you did. Thank you for the forEach solution. I do find it even less clear than using a normal for but the compiler does not complain. – Javier Sep 12 '19 at 13:55