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:
-
for...ofloops on non-array iterables:- Diagnosis: You’re using a
for...ofloop with something that isn’t an array, like aSet,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": trueto thecompilerOptions.{ "compilerOptions": { // ... other options "target": "es5", // or "es3", "es2015", etc. "downlevelIteration": true } } - Why it works: When
downlevelIterationistrue, TypeScript transformsfor...ofloops on non-array iterables into equivalentwhileloops that useiterator.next()calls, which are understood by older JavaScript runtimes.
- Diagnosis: You’re using a
-
Spread syntax (
...) on non-array iterables:- Diagnosis: You’re using the spread syntax to expand an iterable like a
SetorMapinto 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": trueis set in yourtsconfig.jsoncompilerOptions.{ "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.
- Diagnosis: You’re using the spread syntax to expand an iterable like a
-
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": trueintsconfig.json.{ "compilerOptions": { // ... other options "target": "es5", "downlevelIteration": true } } - Why it works:
downlevelIterationensures thatArray.from()is correctly transpiled to use a manual iteration loop when the target environment doesn’t natively support creating arrays from arbitrary iterables.
- Diagnosis: You’re using
-
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": truein yourcompilerOptionsis 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 thevalueproperty of the results to your variables.
- Diagnosis: You’re using destructuring assignment with iterables that are not arrays.
-
Symbol.iteratornot being recognized:- Diagnosis: The core of the iterable protocol is the
Symbol.iteratormethod. 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.iteratorat all (which is rare for anything beyond IE11), you might need a polyfill forSymbol.iteratoror avoid iterable patterns altogether. However,downlevelIteration: trueusually handles the usage of iterables correctly by providing the manual iteration logic, even if theSymbol.iteratoritself isn’t directly available for inspection in the target runtime. The primary fix remainsdownlevelIteration.{ "compilerOptions": { // ... other options "target": "es5", "downlevelIteration": true, "lib": ["es5", "es2015.iterable"] // Explicitly include iterable types if needed } } - Why it works: Explicitly including
es2015.iterablein theliboption ensures TypeScript has the type information for iterables, anddownlevelIterationprovides the runtime compatibility.
- Diagnosis: The core of the iterable protocol is the
-
Incorrect
targetsetting:- Diagnosis: You might have set your
targetto something very old (e.g.,es3ores5) but forgotten that features likeSet,Map, or the iterable protocol were introduced in ES6 (es2015). - Fix: Review your
tsconfig.jsonand ensure thetargetvalue aligns with the JavaScript features you intend to use and the environments you are deploying to. If you need ES6+ features, consider targetinges2015or higher and enablingdownlevelIterationif 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
targetmeans the JavaScript runtime itself might support these features natively.downlevelIterationthen acts as a fallback for environments below that target, ensuring compatibility.
- Diagnosis: You might have set your
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).