Tuplas nomeadas
Você já se deparou com uma tupla no TypeScript e não conseguiu entender o que cada elemento representava? Neste artigo, vamos explorar como as tuplas nomeadas podem tornar seu código mais legível e expressivo.
O que são tuplas?
Tuplas são uma estrutura de dados parecida com arrays, mas com uma diferença fundamental: elas têm um número fixo de elementos, string[] representa um array com um número indefinido de strings.
type StringArray = string[];
const users: StringArray = [
'não importa',
'quantas strings tem aqui',
'sendo string, tudo bem',
'o array poderia até mesmo estar vazio'
];
Já [string, string] representa uma tupla com exatamente duas strings - uma na primeira posição e outra na segunda.
type StringTuple = [string, string];
const users: StringTuple = [
'aqui precisamos obrigatoriamente de duas strings',
'nada mais, nada menos'
];
Enquanto arrays são mais permissivos e a ordem dos elementos não importa, em tuplas o comportamento é o oposto - a ordem é fixa e deve ser respeitada.
Como você definiria uma lista em que o primeiro elemento é uma string e o segundo é um número? Com arrays, você poderia escrever algo como (string | number)[] ou Array<string | number>:
type UserInfo = Array<string | number>;
const userInfo: UserInfo = ['alves', 21];
O problema é que essa abordagem permitiria um número indefinido de strings e numbers dentro do array, e a posição deles não seria fixa - algo como [21, '21'] seria permitido. Para esse cenário, o que você precisa é de uma tupla:
type UserInfo = [string, number];
const userInfo: UserInfo = ['alves', 21, 'oops'];
/* Error: type '[string, number, string]' is not
assignable to type 'UserInfo'.
Source has 3 element(s) but target allows only 2.
/*
type UserInfo = [string, number];
const userInfo: UserInfo = [21, 'alves'];
/* Error: type number is not assignable to type string.
Error: type string is not assignable to type number.
/*
O problema com tuplas anônimas
O grande problema das tuplas anônimas como [string, number] é a falta de clareza. Ao encontrar isso no código, podemos ter algumas dúvidas como:
O que a primeira string representa?
E o number? É um ID? Uma idade? Um timestamp?
Funciona para o compilador, mas nem sempre para humanos que leem o código. É aí que as tuplas nomeadas brilham, elas trazem contexto diretamente na definição do tipo.
Tuplas nomeadas
Tuplas nomeadas (labeled/named tuples) são uma feature introduzida na versão 4.0 do TypeScript. Com elas, podemos dar nomes aos elementos das tuplas, tornando o código mais descritivo e fácil de entender.
A sintaxe é simples: basta colocar um nome antes do tipo do elemento, seguido de dois pontos:
type UserInfo = [userName: string, age: number];
Também podemos usar isso em funções que recebem um parâmetro que é um spread de uma tupla, observe nesse playground como ficam os parâmetros da nossa função createUser sem os elementos nomeados, e como ficam com os elementos nomeados.
E caso tenha surgido a dúvida, sim, também podemos nomear elementos rest de uma tupla, talvez você imagine que a sintaxe é algo como rest: ...type[], mas na verdade a sintaxe é assim:
type UserInfo = [userName: string, age: number, ...rest: unknown[]];
Considerações finais
Um detalhe importante de se lembrar é que tuplas nomeadas tem um propósito de documentação, não muda na prática no uso de tuplas não nomeadas, além do que falei aqui.
Outro ponto importante: quando tuplas nomeadas chegaram, na versão 4.0, todos os elementos da tupla deveriam ser anônimos (não nomeados), ou nomeados, mas isso já não é mais verdade, a partir da versão 5.2 podemos ter ambos, e você pode conferir a implementação disso nessa pull request.
Tuplas nomeadas são uma ferramenta poderosa para melhorar a legibilidade do seu código, use-as com sabedoria e até uma próxima :)