The TS2802: Requires Downlevel Iteration error means your TypeScript compiler is trying to use features that your target JavaScript environment doesn’t support, specifically iterable protocols like for...of loops and spread syntax (...) on non-array collections.

Common Causes and Fixes for TS2802: Requires Downlevel Iteration

This error most commonly pops up when you’re targeting an older JavaScript runtime (like older Node.js versions or Internet Explorer) and your TypeScript code uses features that rely on the ES6+ iterable protocol. TypeScript, by default, won’t automatically transpile these features down to older JavaScript equivalents unless you explicitly tell it to.

Here are the most frequent culprits and how to fix them:

  1. for...of loops on non-array iterables:

    • Diagnosis: You’re using a for...of loop with something that isn’t an array, like a Set, Map, or a custom iterator.
      const mySet = new Set([1, 2, 3]);
      for (const item of mySet) { // TS2802 here if target is < ES6
          console.log(item);
      }
      
    • Fix: In your tsconfig.json, add "downlevelIteration": true to the compilerOptions.
      {
        "compilerOptions": {
          // ... other options
          "target": "es5", // or "es3", "es2015", etc.
          "downlevelIteration": true
        }
      }
      
    • Why it works: When downlevelIteration is true, TypeScript transforms for...of loops on non-array iterables into equivalent while loops that use iterator.next() calls, which are understood by older JavaScript runtimes.
  2. Spread syntax (...) on non-array iterables:

    • Diagnosis: You’re using the spread syntax to expand an iterable like a Set or Map into an array or function arguments.
      const myMap = new Map([['a', 1], ['b', 2]]);
      const arr = [...myMap]; // TS2802 here if target is < ES6
      
    • Fix: Ensure "downlevelIteration": true is set in your tsconfig.json compilerOptions.
      {
        "compilerOptions": {
          // ... other options
          "target": "es5",
          "downlevelIteration": true
        }
      }
      
    • Why it works: Similar to for...of, this flag enables TypeScript to generate code that manually iterates over the source iterable and pushes elements into the resulting array or passes them as arguments, compatible with older JS.
  3. Array.from() with iterables:

    • Diagnosis: You’re using Array.from() to create an array from an iterable that isn’t an array itself.
      const mySet = new Set([1, 2, 3]);
      const arr = Array.from(mySet); // TS2802 here if target is < ES6
      
    • Fix: Again, the solution is to set "downlevelIteration": true in tsconfig.json.
      {
        "compilerOptions": {
          // ... other options
          "target": "es5",
          "downlevelIteration": true
        }
      }
      
    • Why it works: downlevelIteration ensures that Array.from() is correctly transpiled to use a manual iteration loop when the target environment doesn’t natively support creating arrays from arbitrary iterables.
  4. Destructuring assignment with iterables:

    • Diagnosis: You’re using destructuring assignment with iterables that are not arrays.
      const mySet = new Set([1, 2, 3]);
      const [first, second] = mySet; // TS2802 here if target is < ES6
      
    • Fix: The presence of "downlevelIteration": true in your compilerOptions is the key.
      {
        "compilerOptions": {
          // ... other options
          "target": "es5",
          "downlevelIteration": true
        }
      }
      
    • Why it works: TypeScript will convert destructuring on non-array iterables into a series of iterator.next() calls and assign the value property of the results to your variables.
  5. Symbol.iterator not being recognized:

    • Diagnosis: The core of the iterable protocol is the Symbol.iterator method. If your target JavaScript environment doesn’t support Symbols or the standard way of accessing them, TypeScript might fail to recognize iterables correctly. This is less common with modern targets but can occur with extremely old ones or custom environments.
    • Fix: If you must target an environment that doesn’t support Symbol.iterator at all (which is rare for anything beyond IE11), you might need a polyfill for Symbol.iterator or avoid iterable patterns altogether. However, downlevelIteration: true usually handles the usage of iterables correctly by providing the manual iteration logic, even if the Symbol.iterator itself isn’t directly available for inspection in the target runtime. The primary fix remains downlevelIteration.
      {
        "compilerOptions": {
          // ... other options
          "target": "es5",
          "downlevelIteration": true,
          "lib": ["es5", "es2015.iterable"] // Explicitly include iterable types if needed
        }
      }
      
    • Why it works: Explicitly including es2015.iterable in the lib option ensures TypeScript has the type information for iterables, and downlevelIteration provides the runtime compatibility.
  6. Incorrect target setting:

    • Diagnosis: You might have set your target to something very old (e.g., es3 or es5) but forgotten that features like Set, Map, or the iterable protocol were introduced in ES6 (es2015).
    • Fix: Review your tsconfig.json and ensure the target value aligns with the JavaScript features you intend to use and the environments you are deploying to. If you need ES6+ features, consider targeting es2015 or higher and enabling downlevelIteration if you still need to support older environments than your chosen target.
      {
        "compilerOptions": {
          // ... other options
          "target": "es2015", // Or "es2016", "es2017", etc.
          "downlevelIteration": true // Still useful for broader compatibility
        }
      }
      
    • Why it works: Setting a higher target means the JavaScript runtime itself might support these features natively. downlevelIteration then acts as a fallback for environments below that target, ensuring compatibility.

The most robust solution for TS2802 is almost always to add "downlevelIteration": true to your compilerOptions in tsconfig.json, especially if your target is es5 or lower.

After fixing this, the next error you’ll likely encounter is related to other ES6+ features not being supported by your target environment, such as Promises, async/await, or classes, which will require further configuration (like polyfills or higher target values).

Want structured learning?

Take the full Typescript course →