Website-Suche

javascript - TypeScript: wie man ein Array fester Größe für die Typprüfung zur Compile-Zeit deklariert


Update: Diese Überprüfungen sind für die Kompilierzeit gedacht, nicht zur Laufzeit. In meinem Beispiel werden alle fehlgeschlagenen Fälle bereits zur Kompilierzeit erfasst, und ich erwarte ein ähnliches Verhalten für die anderen should-fail-Fälle.

Angenommen, ich schreibe eine tabellenähnliche Klasse, bei der ich möchte, dass alle Mitglieder der Klasse Arrays derselben Länge sind, so etwas wie:

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
}

Die bislang nächstliegende Lösung, die ich gefunden habe, ist:

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

Irgendwelche besseren Ideen?

Antwort #1

Update 2: Ab Version 3.4 ist das, wonach der OP gefragt hat, jetzt mit einer prägnanten Syntax vollständig möglich (Playground-Link):

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

Update 1: Ab Version 2.7 kann TypeScript jetzt zwischen Listen unterschiedlicher Größen unterscheiden.

Ich denke nicht, dass es möglich ist, die Länge eines Tupels typmäßig zu überprüfen. Hier ist die Meinung des Autors von TypeScript zu diesem Thema.

Ich würde argumentieren, dass das, wonach Sie fragen, nicht notwendig ist. Angenommen, Sie definieren diesen Typ

type StringTriplet = [string, string, string]

und definieren Sie eine Variable dieses Typs:

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

Man kann aus diesem Tripel nicht mehr Variablen herausbekommen, z. B.

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

wird einen Fehler erzeugen, während dies wie erwartet nicht der Fall ist:

const [one, two, three] = a;

Die einzige Situation, in der ich denke, dass das Fehlen der Fähigkeit, die Länge zu begrenzen, zu einem Problem wird, ist zum Beispiel, wenn man über das Tripel map.

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

und erwarten, dass result 3 Elemente hat, obwohl es tatsächlich mehr als 3 haben kann. In diesem Fall behandeln Sie a jedoch sowieso als Sammlung und nicht als Tupel, sodass dies kein korrekter Anwendungsfall für die Tupel-Syntax ist.

Antwort #2

Aus Typescript: Kann ich einen n-langen Tupeltyp definieren?, programmatisch, mit dynamischer Länge:

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

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

Verwandte Artikel