HOWTO · JavaScript

Tuples en JavaScript : tableaux, objets et TypeScript

JavaScript ne possède pas de type tuple natif. Utilisez selon le besoin un tableau, un objet, Object.freeze(), la déstructuration ou un tuple TypeScript.

Sur cette page

JavaScript ne possède pas de valeur tuple native à l’exécution. Pour regrouper quelques valeurs ordonnées, comme des coordonnées, utilisez un tableau et la déstructuration. Préférez un objet lorsque les noms rendent les données plus claires. Si le programme doit empêcher les modifications directes à l’exécution, gelez le tableau ; si vous devez contrôler une longueur fixe et le type de chaque élément pendant le développement, utilisez un tuple TypeScript.

Utiliser un tableau pour une paire ordonnée

Un tableau convient comme valeur similaire à un tuple lorsque chaque position a un sens stable. Cette fonction renvoie le minimum, puis le maximum :

function minMax(values) {
  return [Math.min(...values), Math.max(...values)];
}

const [minimum, maximum] = minMax([7, 3, 12]);
console.log(minimum, maximum);

Résultat :

3 12

La déstructuration donne des noms locaux utiles aux positions. Documentez leur ordre pour les appelants. JavaScript ne contrôle ni la longueur du tableau ni le type des éléments ; validez donc les données externes avant de vous fier à ce contrat positionnel.

Geler un tableau uniquement si la protection à l’exécution est nécessaire

const empêche de réaffecter la variable, mais pas de modifier le tableau qu’elle référence. Object.freeze() gèle le tableau lui-même :

"use strict";

const point = Object.freeze([48.8566, 2.3522]);

console.log(point[0], point[1], Object.isFrozen(point));
// point[0] = 0; // TypeError in strict mode
// point.push(3); // TypeError

Résultat :

48.8566 2.3522 true

Object.freeze() renvoie le même objet au lieu d’en créer une copie. Si l’appelant reste propriétaire du tableau d’entrée, copiez-le avant de le geler :

function asFrozenPoint(value) {
  if (
    !Array.isArray(value) ||
    value.length !== 2 ||
    !value.every(Number.isFinite)
  ) {
    throw new TypeError("Expected two finite coordinates");
  }

  return Object.freeze([...value]);
}

Le gel est superficiel. Il empêche de modifier les éléments directs, la longueur et les propriétés propres du tableau, mais les objets imbriqués restent modifiables :

const settings = Object.freeze([{ theme: "light" }]);

settings[0].theme = "dark";
console.log(settings[0].theme);

Résultat :

dark

Ne présentez donc pas une structure imbriquée gelée superficiellement comme entièrement immuable. Un gel profond doit parcourir les valeurs imbriquées et gérer les cycles ; ne l’ajoutez que si cette garantie est réellement nécessaire.

Utiliser un objet lorsque les noms sont plus clairs

Les positions deviennent fragiles lorsque la valeur contient plusieurs chaînes, booléens, champs facultatifs ou champs susceptibles d’évoluer :

function createUser() {
  return { id: 42, name: "Ada", active: true };
}

const { id, name, active } = createUser();

Un tableau convient aux paires compactes et connues, telles que [x, y] ou les entrées [key, value] de Object.entries(). Un objet est plus sûr si l’appelant devrait autrement mémoriser la signification de chaque indice.

Object.entries() fournit déjà une paire positionnelle documentée. La déstructuration rend les deux positions explicites à l’endroit où elles sont utilisées :

for (const [key, value] of Object.entries({ theme: "light" })) {
  console.log(`${key}: ${value}`);
}

Résultat :

theme: light

Utiliser TypeScript pour vérifier le contrat du tuple

TypeScript peut exprimer la longueur, l’ordre et le type des éléments :

const point: readonly [number, number] = [48.8566, 2.3522];

readonly interdit les écritures dans le code TypeScript. Après compilation, la valeur reste un tableau JavaScript ordinaire et n’est pas gelée à l’exécution. Combinez un tuple TypeScript et Object.freeze() seulement si vous avez besoin à la fois du contrôle statique et de la protection à l’exécution.

Résumé

Les tableaux JavaScript peuvent servir de tuples par convention et se déstructurent facilement. Choisissez un objet pour des champs nommés, Object.freeze() pour une protection superficielle à l’exécution et un tuple TypeScript pour contrôler statiquement la longueur et les types.