Recentemente, vi um tweet de Jamie Kyle sobre o uso de desestruturação, parâmetros padrão e tipos embutidos:
Esse tweet e alguns componentes do React que vi recentemente em meu trabalho diário me inspiraram a escrever esta postagem no blog. Quero mostrar a você como usar tipos de desestruturação e embutidos pode tornar seu TypeScript menos legível!
Como é a definição da função TypeScript?
Em JavaScript e TypeScript, você pode definir uma função usando a palavra-chave function
ou a função lambda/seta. Ambas as formas são válidas, mas têm suas diferenças. Vamos dar uma olhada na função simples sendMessage
. A lógica de implementação não é relevante para nós.
// sendMessage function written using `function` keyword function sendMessage(message: string) { // function logic } // same sendMessage written as arrow function const sendMessage = (message: string) => { // function logic };
Quando a definição da função é bastante simples, a função aceita alguns parâmetros de um tipo diferente. Se forem primitivos como strings ou números, tudo é legível.
Digamos que você queira passar algumas informações adicionais junto com o conteúdo de sua mensagem para a função sendMessage
.
function sendMessage(message: { content: string; senderId: string; replyTo?: string; }) { // you can assess content using `message.content` here }
Como você pode ver, o TypeScript permite que você escreva uma definição de tipo embutida para o objeto de message
que deseja passar sem especificar o tipo usando a palavra-chave type
ou interface
.
Vamos adicionar Destructuring. Quando você passa um grande objeto de message
para sua função, o TypeScript permite separar os argumentos passados para reduzir o padrão de código da variável de message
repetida muitas vezes.
function sendMessage({ content, senderId, replyTo, }: { content: string; senderId: string; replyTo?: string; }) { // you have access to `content` directly }
Por que acho que é uma má ideia e como você pode torná-la melhor?
Pode parecer uma boa ideia, afinal não é preciso escrever message
vezes, certo? Acontece que não é tão bom. Vamos falar sobre 5 razões pelas quais eu acho que é um antipadrão.
1. Você não tem certeza de onde vêm seus dados
Ao ler o corpo da função, você vê senderId
e precisa verificar novamente para ter certeza de onde essa função vem. É passado como um argumento ou calculado em algum lugar da função?
2. É difícil escrever documentação
Não há lugar natural para escrever comentários de documentação quando todos os tipos são limitados pela desestruturação na definição da função. Você pode escrever comentários entre cada campo de tipo, mas isso torna toda a definição da função ainda mais longa. Está ativamente desencorajando você a escrever um resumo rápido dos dados que está passando.
3. É difícil passar esses dados adiante
Quando seus dados são desestruturados, você precisa estruturá-los novamente em um novo objeto se quiser passá-los adiante. Isso desencoraja a criação de funções auxiliares menores e a dependência da composição para construir a lógica da função principal.
4. Você não pode reutilizar tipos de argumentos fora desta função
Se você precisar reutilizar seus argumentos de função em funções auxiliares ao compor sua lógica de função principal, deverá digitar o mesmo conjunto de tipos repetidamente. Isso torna mais fácil não escrever tipos.
5. É preciso muito espaço
Vamos encarar. São apenas muitas linhas de código que ocupam muito espaço na tela. Além disso, ele se concentra nos detalhes da implementação – o tipo interno dos argumentos que você está passando para uma função, que na maioria das vezes não é relevante quando você está olhando para essa função.
Basta criar um tipo para ele
Extrair o tipo e colocá-lo logo acima da função o torna muito mais legível. Há um local para comentários de documentação, você pode reutilizar esse tipo em alguma outra função auxiliar e alterar a definição de tipo em um local, se necessário.
/** * Message to send using XYZ API */ export type MessageToSend = { /** * Markdown string of the user's message */ content: string; /** * Id of the sender user */ senderId: string; /** * Other message ID if this is a reply */ replyTo?: string; }; function sendMessage(message: MessageToSend) { // function logic } function getUserIdsToNotify(message: MessaageToSend) { // function logic }
Recursos
Encontre uma lista de recursos que usei ao pesquisar esta postagem no blog: