Tipi di tuple dattiloscritte

Come digitare al meglio le tuple in Typescript 4.2 e versioni successive

Uno sguardo più da vicino alle tuple Typescript

Come rapido promemoria, una tupla nella sua definizione più elementare è solo una struttura dati composta da più parti. Nell'ambito dell'utilizzo delle tuple nei linguaggi di programmazione, come Typescript, è anche importante notare che i dati sono più comunemente ordinati.

Un semplice esempio mostra come vengono definite le tuple in Typescript.

// This tuple is defined as a set
// of two numbers.
const scores: [number, number] = [1, 2];

// For comparison, this tuple consists
// of three elements, each of a different
// type. Not that the ordered nature of
// tuples in TS becomes very clear here.
const result: [string, number, boolean] = ["id", 101, false];

// And as a "nice-to-know", you can even
// provide lables for the tuple elements.
// This doesn't have any effect on the typesystem
// itself and only (may) improve documentation.
const output: [id: number, name: string] = [101, "Tom"];

Tuple con elementi opzionali

Poiché Typescript è migliorato nel tempo, anche la sua implementazione delle tuple è migliorata. Non devi solo definire elementi che devono essere obbligatori. Ora puoi anche digitare gli elementi come facoltativi. Se non lo sai, Typescript utilizza il punto interrogativo come simbolo generale per definire gli elementi come opzionali, il che significa che possono essere disponibili in fase di esecuzione, ma non è necessario.

Un altro esempio dimostra cosa intendo con questo.

// Similar to our previous example, but in this
// case the the tuple's last element doesn't have
// to be provided (or can be undefined at runtime).
type Tuple = [id: number, name?: string];

const a: Tuple = [101];
const b: Tuple = [42, "Tom"];

Elementi di riposo nelle tuple dattiloscritte

Con gli elementi di riposo, hai un tipo molto potente a portata di mano che contrassegna tutti gli elementi successivi nella tupla di un dato tipo. Quindi supponiamo che tu abbia una tupla con due elementi e il secondo definito come elemento di riposo, puoi quindi fornire 2 + n elementi in fase di esecuzione a questa variabile di tupla.

Per restringere la definizione, fino a poco tempo tale elemento era consentito solo alla fine di una tupla. Ciò ha senso, poiché ciò consente di fornire un numero qualsiasi di elementi in fase di esecuzione del tipo di riposo, ma renderebbe le cose molto complicate per distinguere tra l'elemento di riposo e un altro elemento tipizzato.

// This example might be a tuple type
// for a CLI similar to Node.js. The first
// two elements are system-internal.
//
// Starting from the 3rd element, a user can
// provide as much arguments as desired, yet
// we can still cleanly handle it with TS. Nice!
let input: [number, boolean, ...string[]];

// Just to show that we really can provide any
// number of rest elements, including 0.
e = [0, false, "max-cache", "1024", "debug", "false"];
e = [0, false];
e = [0, false, "verbose"];

Elemento di pausa principale o centrale nei tipi di tupla

Facendo avanzare l'elemento rest per le tuple, è possibile creare implementazioni ancora più sofisticate da quando è stato rilasciato Typescript 4.2. E qui devo scusarmi: con poche frasi in anticipo, ho scritto come sia obbligatorio utilizzare un elemento di riposo solo come ultimo. Questa restrizione in realtà non è più vera da Typescript 4.2, poiché ora puoi posizionare elementi di riposo quasi ovunque in una tupla.

Ma con solo poche restrizioni, Typescript ora fornisce una sintassi molto carina per le tuple avanzate. Gli elementi di riposo possono verificarsi ovunque all'interno di una tupla purché siano conformi alle due regole seguenti

  • non è seguito da un elemento opzionale
  • nessun altro elemento di pausa segue il primo

Prima di parlare troppo di teoria, vediamo per un esempio.

// And here comes the fancy part: rest elements
// *not only* at the end of a tuple.
// 
// Note: this example is taken directly from the
// TS documentation. For more details, check out the
// links in the addendum.
let foo: [...string[], number];

foo = [123];
foo = ["hello", 123];
foo = ["hello!", "hello!", "hello!", 123];

let bar: [boolean, ...string[], boolean];

bar = [true, false];
bar = [true, "some text", false];
bar = [true, "some", "separated", "text", false];

// And here's an example that shows how the
// type system would catch your errors:
interface Clown { /*...*/ }
interface Joker { /*...*/ }

let StealersWheel: [...Clown[], "me", ...Joker[]];
//                                    ~~~~~~~~~~ Error!
// A rest element cannot follow another rest element.

let StringsAndMaybeBoolean: [...string[], boolean?];
//                                        ~~~~~~~~ Error!
// An optional element cannot follow a rest element.

L'elemento di riposo di questo articolo

Chiudendo questa guida compatta sulle tuple in Typescript, abbiamo dato un'occhiata all'implementazione di base e poi abbiamo esaminato alcuni esempi più avanzati per vedere come Typescript consente un sistema di tipi molto flessibile quando si tratta di tuple. Spero che l'articolo ti sia piaciuto e se sei curioso di saperne di più, dai un'occhiata agli altri post suggeriti in basso.

Suggerimenti

Correlati

Addendum

Lingue