web-dev-qa-db-fra.com

TypeScript: comment déclarer un tableau de taille fixe pour la vérification de type au moment de la compilation

pdate: Ces vérifications sont destinées à temps de compilation, pas à runtime. Dans mon exemple, les cas ayant échoué sont tous interceptés au moment de la compilation, et je m'attends à un comportement similaire pour les autres cas devrait échouer.

Supposons que j'écris une classe semblable à une table où je veux que tous les membres de la classe soient des tableaux de la même longueur, quelque chose comme:

class MyClass {
  tableHead:  string[3]; // expect to be a 3 element array of strings
  tableCells: number[3]; // expect to be a 3 element array of numbers
}

La solution la plus proche que j'ai trouvée jusqu'à présent est:

class MyClass {
  tableHead:  [string, string, string];
  tableCells: [number, number, number];
}

let bar = new MyClass();
bar.tableHead = ['a', 'b', 'c']; // pass
bar.tableHead = ['a', 'b'];      // fail
bar.tableHead = ['a', 'b', 1];   // fail

// BUT these also pass, which are expected to fail at compile time
bar.tableHead = ['a', 'b', 'c', 'd', 'e']; // pass
bar.Push('d'); // pass
bar.Push('e'); // pass

De meilleures idées?

10
benjaminz

Mise à jour 2: à partir de la version 3.4, ce que l'OP demandait est maintenant entièrement possible avec une syntaxe succincte ( lien Playground ):

class MyClass {
  tableHead: readonly [string, string, string]
  tableCells: readonly [number, number, number]
}

Mise à jour 1: à partir de la version 2.7, TypeScript peut désormais distinguer les listes de tailles différentes .

Je ne pense pas qu'il soit possible de vérifier la longueur d'un tuple. Ici est l'opinion de l'auteur de TypeScript à ce sujet.

Je dirais que ce que vous demandez n'est pas nécessaire. Supposons que vous définissiez ce type

type StringTriplet = [string, string, string]

et définir une variable de ce type:

const a: StringTriplet = ['a', 'b', 'c']

Vous ne pouvez pas extraire plus de variables de ce triplet, par ex.

const [one, two, three, four] = a;

donnera une erreur alors que ce n'est pas comme prévu:

const [one, two, three] = a;

La seule situation où je pense que le manque de capacité à contraindre la longueur devient un problème est par exemple lorsque vous map sur le triplet

const result = a.map(/* some pure function */)

et attendez-vous à ce que result ait 3 éléments alors qu'en fait il peut en avoir plus de 3. Cependant, dans ce cas, vous traitez a comme une collection au lieu d'un Tuple de toute façon, ce n'est donc pas une bonne cas d'utilisation de la syntaxe Tuple.

11
Huy Nguyen

De TypeScript: puis-je définir un type de tuple de longueur n? , par programme, avec une longueur dynamique:

type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & { length: TLength };

type Tuple9<T> = Tuple<T, 9>;
2
cancerbero

Voici un exemple simple d'une classe pour contrôler la longueur de son tableau interne. Ce n'est pas infaillible (lors de l'obtention/du réglage, vous voudrez peut-être vous demander si vous êtes un clonage peu profond/profond, etc.

https://jsfiddle.net/904d9jhc/

class ControlledArray {

  constructor(num) {
    this.a = Array(num).fill(0); // Creates new array and fills it with zeros
  }

  set(arr) {
    if (!(arr instanceof Array) || arr.length != this.a.length) {
      return false;
    }
    this.a = arr.slice();
    return true;
  }

  get() {
    return this.a.slice();
  }

}

$( document ).ready(function($) {

  var m = new ControlledArray(3);

  alert(m.set('vera')); // fail
  alert(m.set(['vera', 'chuck', 'dave'])); // pass

  alert(m.get()); // gets copy of controlled array

});
0
Chris Cousins