TypeError: Reduce of empty array with no initial value

Message

TypeError: reduce of empty array with no initial value

Type d'erreur

Quel est le problème ?

En JavaScript, il existe plusieurs fonctions qui permettent de réduire un tableau :

Ces fonctions utilisent un argument optionnel valeurInitiale (qui sera utilisée comme premier argument pour le premier appel du callback). Toutefois, si aucune valeur initiale explicite est fournie, la méthode utilisera le premier élément de l'objet Array / TypedArray comme valeur initiale. Cette exception est déclenchée lorsqu'on souhaite réduire un tableau vide car aucune valeur initiale n'a été fournie.

Exemples

Exemples invalides

Ce problème se produit lorsqu'on combine une méthode de filtrage (Array.prototype.filter(), TypedArray.prototype.filter()) qui retire tous les éléments du tableau. Si on applique ensuite une réduction, il n'y aura pas de valeur initiale.

js
var ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x > 0) // cet appel retire tous les éléments
  .reduce((x, y) => x + y); // aucun ne peut alors être utilisé comme valeur initiale

Cela peut également se produire si on utilise un sélecteur avec une coquille ou que la liste contient un nombre d'élément inattendu:

js
var names = document.getElementsByClassName("names");
var name_list = Array.prototype.reduce.call(
  names,
  (acc, name) => acc + ", " + name,
);

Exemples valides

On peut résoudre ces problèmes de deux façons.

On peut fournir une valeur initiale qui soit l'élément neutre de la réduction (par exemple 0 si on additionne, 1 si on multiplie ou la chaîne vide si on concatène du texte).

js
var ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x > 0) // removes all elements
  .reduce((x, y) => x + y, 0); // the initial value is the neutral element of the addition

On peut également gérer le cas où le tableau est vide, avant d'appeler reduce ou dans le callback après avoir ajouté une valeur initiale.

js
var names = document.getElementsByClassName("names");

var nameList1 = "";
if (names1.length >= 1)
  nameList1 = Array.prototype.reduce.call(
    names,
    (acc, name) => acc + ", " + name,
  );
// nameList1 == "" lorsque names est vide

var nameList2 = Array.prototype.reduce.call(
  names,
  (acc, name) => {
    if (acc == "")
      // la valeur initiale
      return name;
    return acc + ", " + name;
  },
  "",
);
// nameList2 == "" lorsque names est vide

Voir aussi