Looping

{#each} block allows you to loop only array or array-like object (i.e. it has a .length property).

Here are some examples if you want to loop through data structures besides array.

Looping a map

You can use spread operator [...value] for Map to get an array of key value pairs.

<script>
  const map = new Map([['.svelte', 'Svelte'], ['.js', 'JavaScript']]);
</script>

{#each [...map] as [key, value]}
	<div>
		{key}: {value}
  </div>
{/each}

Both Map.keys() and Map.values() method return an iterable. To use {#each} with iterable, you can use spread operator [...value] on the iterable.

<script>
  const map = new Map([['.svelte', 'Svelte'], ['.js', 'JavaScript']]);
</script>

{#each [...map.keys()] as key}
	<div>
		{key}
  </div>
{/each}

{#each [...map.values()] as value}
	<div>
		{value}
  </div>
{/each}

Looping a set

You can use spread operator [...value] for Set to get an array of items.

<script>
  const set = new Set(['.svelte', '.js']);
</script>

{#each [...set] as item}
	<div>
		{item}
	</div>
{/each}

Looping a string

String is considered an array-like object as it has .length property.

<script>
  const string = 'Svelte';
</script>

{#each string as character}
	<div>
		{character}
	</div>
{/each}

Looping a generator function

Generator function function* returns a generator object, which conforms to both the iterable protocol and the iterator protocol.

To use {#each} with generator function, you can use spread operator [...value] on the generator.

<script>
	function* generator() {
		yield '.svelte';
		yield '.js';
	}
</script>

{#each [...generator()] as item}
	<div>
		{item}
	</div>
{/each}

Binding to spreaded item

Once you spread a Map, Set, Generator, or any Iterable, you are creating a new array, and therefore binding (bind:) with the item may not work anymore.

<script>
  const map = new Map([['.svelte', 'Svelte'], ['.js', 'JavaScript']]);
</script>

{#each [...map] as [key, value]}
  <!-- You can't change the value of the input, nor the value in the map -->
  <input bind:value={value} />
{/each}

To workaround this, you can use on:input listener

<script>
  const map = new Map([['.svelte', 'Svelte'], ['.js', 'JavaScript']]);
</script>

{#each [...map] as [key, value]}
  <input
    {value}
    on:input={(event) => {
      map.set(key, event.currentTarget.value);
      map = map;
    }}
  />
{/each}