Skip to content

Fixing "Type 'Set<unknown>' can only be iterated through when using the '--downlevelIteration' flag"

Problem

When working with TypeScript and trying to use the spread operator with Set objects to create arrays of unique values:

typescript
const uniqueValues = [...new Set(someArray)];

You may encounter this TypeScript error:

Type 'Set<unknown>' can only be iterated through when using the '--downlevelIteration' flag 
or with a '--target' of 'es2015' or higher

This occurs because the spread operator syntax for iterating over Set objects requires JavaScript features that weren't available in older ECMAScript versions.

Solutions

The most straightforward solution is to update your tsconfig.json file to use a modern ECMAScript target:

json
{
  "compilerOptions": {
    "target": "es2015", // or "es6", "es2017", "es2020", etc.
    // other options...
  }
}

TIP

The es2015 target includes native support for Sets and the spread operator, eliminating the need for the --downlevelIteration flag.

2. Use Array.from() Instead

If you can't change your TypeScript target, use Array.from() to convert the Set to an array:

typescript
// Instead of: [...new Set(values)]
const uniqueValues = Array.from(new Set(values));

This approach works with older ECMAScript targets and doesn't require the spread operator.

3. Alternative: Filter Method

For compatibility with very old JavaScript environments, you can use the filter() method:

typescript
const uniqueValues = values.filter((value, index, array) => {
  return array.indexOf(value) === index;
});

While this approach works, it's less efficient for large arrays compared to using a Set.

4. Complete Configuration Example

For React projects with TypeScript, here's a recommended configuration:

json
{
  "compilerOptions": {
    "target": "es2015",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

React Note

If you update from es5 to a newer target in a React project, you might also need to update React.Node to React.ReactNode in your type annotations.

Understanding the Issue

The error occurs because:

  1. The spread operator (...) on iterable objects like Set requires ES2015+ features
  2. TypeScript's default target might be set to older versions (like es5) for compatibility
  3. The --downlevelIteration flag enables this functionality for older targets but adds runtime overhead

Best Practices

  1. Prefer modern targets: Use at least es2015 for new projects
  2. Use Array.from() for compatibility: When supporting older environments
  3. Consider performance: Set operations are generally faster than array filtering for deduplication

Example Implementation

Here's the correct way to get unique IDs from an array of objects:

typescript
// Original problematic code
const uniqueMuscle = workoutexercices.map((exercice: any) => {
  let exercicesId = exercice.id;
  exercicesId = [...new Set(exercicesId)]; // Error here
  return exercicesId;
});

// Fixed version
const uniqueMuscleIds = Array.from(
  new Set(workoutexercices.map(exercice => exercice.id))
);

This approach extracts all IDs first, then creates a Set to remove duplicates, and finally converts back to an array - all in a single efficient operation.

Choose the solution that best fits your project's compatibility requirements and performance needs. For most modern applications, updating the TypeScript target to es2015 or higher is the recommended approach.