Search code examples
javascripttypescripttslintfor-of-loop

Expected a 'for-of' loop instead of a 'for' loop while doing modifications


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


Solution

  • 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)] = ...;
    }