This error occurs when TypeScript cannot guarantee that a type is iterable, typically when targeting ES5/ES3 without proper configuration. Enable downlevelIteration in tsconfig.json to fix it.
This error appears when you try to use iteration features (like `for...of` loops, spread operators, or array destructuring) on a type that TypeScript cannot verify as iterable. The error is most common when compiling to ES5 or ES3 targets because these older JavaScript versions don't natively support the Symbol.iterator protocol. TypeScript needs to ensure that any type you iterate over has a `[Symbol.iterator]()` method that returns an iterator object. When targeting modern JavaScript (ES6+), arrays and other built-in iterables automatically have this method. However, when targeting ES5 or ES3, TypeScript requires additional configuration to safely transform iteration code into ES5-compatible loops. The error often surfaces when working with arrays that might be undefined, spreading values from objects into arrays, or using iteration on custom types without proper iterator implementation.
The most common fix is to enable the downlevelIteration compiler option. This tells TypeScript to emit more compliant (but verbose) iteration code for ES5/ES3 targets.
Open your tsconfig.json and add or update the downlevelIteration option:
{
"compilerOptions": {
"target": "ES5",
"downlevelIteration": true,
// ... other options
}
}This option allows TypeScript to properly handle iteration when targeting older JavaScript versions. Note that enabling this adds helper functions to your compiled output, slightly increasing bundle size.
If you don't need to support very old browsers, the cleanest solution is to target a modern JavaScript version that natively supports iterators.
Update your tsconfig.json:
{
"compilerOptions": {
"target": "ES2015", // or ES2016, ES2017, ES2018, etc.
// ... other options
}
}ES2015 (ES6) and later versions have native Symbol.iterator support, so TypeScript doesn't need to transform your iteration code. This results in cleaner output and smaller bundle sizes.
If you're trying to spread or iterate over values that might be undefined, add proper null checks or provide fallback values.
Use the nullish coalescing operator to provide a default empty array:
// Before (error-prone)
const combined = [...array1, ...array2];
// After (safe)
const combined = [...(array1 ?? []), ...(array2 ?? [])];Or use optional chaining with a fallback:
// For function results that might be undefined
const results = [...(getData() ?? [])];
// For optional properties
const items = [...(obj.items ?? [])];This ensures you're always spreading an actual array, not undefined or null.
If you're working with custom types that should be iterable, ensure they properly implement the iterable interface.
For a custom iterable class:
class CustomIterable<T> implements Iterable<T> {
private items: T[];
constructor(items: T[]) {
this.items = items;
}
[Symbol.iterator](): Iterator<T> {
let index = 0;
const items = this.items;
return {
next(): IteratorResult<T> {
if (index < items.length) {
return { value: items[index++], done: false };
}
return { value: undefined as any, done: true };
}
};
}
}
// Now this works
const iterable = new CustomIterable([1, 2, 3]);
const array = [...iterable];Make sure your type implements Iterable<T> and provides the [Symbol.iterator]() method.
If you've enabled downlevelIteration but still get runtime errors in old browsers, you need a Symbol polyfill.
Install core-js:
npm install core-jsImport the Symbol polyfill at your application entry point:
// At the top of your main file (e.g., index.ts)
import 'core-js/features/symbol';
import 'core-js/features/symbol/iterator';Or if using the full core-js:
import 'core-js/stable';This ensures that Symbol.iterator exists in the runtime environment, even in browsers that don't support it natively.
Ensure your TypeScript lib configuration includes the appropriate libraries for your target environment.
Check your tsconfig.json:
{
"compilerOptions": {
"target": "ES5",
"lib": ["ES2015", "DOM"],
"downlevelIteration": true
}
}Including "ES2015" in the lib array gives you the type definitions for iterators even when targeting ES5. This allows TypeScript to understand iteration protocols while still outputting ES5-compatible code.
If you don't specify lib, TypeScript defaults to the standard library matching your target, which might not include iterator types.
Understanding downlevelIteration overhead: When you enable downlevelIteration, TypeScript emits helper functions to check for Symbol.iterator at runtime. For arrays, this adds approximately 200-300 bytes per bundle (after minification). If bundle size is critical and you only iterate over arrays, you might prefer to refactor your code to use traditional for loops instead.
Async iterators: The same principles apply to async iteration (for await...of). You'll need downlevelIteration enabled and potentially a Symbol.asyncIterator polyfill. For ES5/ES3 targets with async iteration, you must also set the target to at least ES2015 for async/await support, or use a transpiler like Babel.
Generator functions: If you're using generator functions that should be iterable, they also require downlevelIteration when targeting ES5/ES3. The emitted code will be significantly more complex as TypeScript needs to transform the generator into a state machine.
Type narrowing issues: Sometimes this error appears due to overly broad type unions. For example, string[] | undefined won't be iterable without proper narrowing. Consider using type guards or definite assignment assertions if you know the value will always be defined at runtime.
Third-party libraries: Some libraries might export types that don't properly declare iterator support. If you encounter this error with a library type, check if there's an updated version with better type definitions, or consider wrapping the value to ensure proper typing.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript