Tipos de tuplas mecanografiadas

Cómo escribir mejor tuplas en TypeScript 4.2 y versiones posteriores

Una mirada más cercana a las tuplas de TypeScript

Como recordatorio rápido, una tupla en su definición más básica es solo una estructura de datos que consta de varias partes. En el ámbito del uso de tuplas en lenguajes de programación, como TypeScript, también es importante tener en cuenta que los datos se ordenan con mayor frecuencia.

Un ejemplo simple muestra cómo se definen las tuplas en 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"];

Tuplas con elementos opcionales

A medida que TypeScript mejoraba con el tiempo, también lo hacía su implementación de tuplas. No solo tiene que definir los elementos que tienen que ser obligatorios. Ahora también puede escribir elementos como opcional. Si no lo sabe, TypeScript usa el signo de interrogación como símbolo general para definir elementos como opcionales, lo que significa que pueden estar disponibles en tiempo de ejecución, pero no es necesario.

Otro ejemplo demuestra lo que quiero decir con eso.

// 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"];

Elementos de descanso en tuplas de TypeScript

Con los elementos de descanso, tiene un tipo muy poderoso a mano que marca todos los elementos siguientes en la tupla de un tipo determinado. Entonces, digamos que tiene una tupla con dos elementos y el segundo definido como un elemento de descanso, luego puede proporcionar 2 + n elementos en tiempo de ejecución a esta variable de tupla.

Para reducir la definición, hasta hace poco tiempo, un elemento de este tipo solo se permitía al final de una tupla. Esto tiene sentido, ya que le permite proporcionar cualquier número de elementos en tiempo de ejecución del tipo de descanso, pero haría las cosas muy complicadas para distinguir entre el elemento de descanso y otro elemento escrito más.

// 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 de descanso inicial o intermedio en tipos de tuplas

Avanzando en el resto del elemento para tuplas, puede crear implementaciones aún más sofisticadas desde que se lanzó Typecript 4.2. Y tengo que disculparme aquí: solo unas pocas oraciones antes, escribí cómo es obligatorio usar un elemento de descanso solo como el último. Esta restricción ya no es verdadera desde Typescript 4.2, ya que ahora puede colocar elementos de descanso en casi cualquier lugar de una tupla.

Pero con solo unas pocas restricciones, Typecript ahora proporciona una sintaxis muy agradable para tuplas avanzadas. Los elementos de descanso pueden ocurrir en cualquier lugar dentro de una tupla siempre que cumplan con las siguientes dos reglas

  • no va seguido de un elemento opcional
  • ningún otro elemento de descanso sigue al primero

Antes de hablar demasiado de teoría, veamos un ejemplo.

// 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.

El resto del elemento de este artículo

Cerrando esta guía compacta sobre tuplas en Typecript, hemos echado un vistazo a la implementación básica y luego analizamos algunos ejemplos más avanzados para ver cómo Typecript permite un sistema de tipos muy flexible cuando se trata de tuplas. Espero que haya disfrutado del artículo y, si tiene curiosidad por obtener más información, consulte las publicaciones sugeridas a continuación.

Sugerencias

Relacionados

Adenda

Idiomas