A maldição dos parâmetros omitidos em TypeScript
\nVocê já escreveu uma função com dez parâmetros opcionais e depois tentou passar apenas o quinto e o décimo? E imediatamente recebeu um erro de compilação ou, pior ainda, um erro lógico silencioso? Familiar?
\nNo Stack Overflow, esta pergunta acumulou milhares de visualizações. Desenvolvedores em TypeScript constantemente tropeçam no mesmo obstáculo: como passar um parâmetro opcional, ignorando outro? Afinal, a sintaxe padrão não permite isso – os parâmetros são passados por posição, não por nome.
\nHoje vamos resolver essa dor de uma vez por todas. Vou mostrar 4 maneiras funcionais de resolver o problema: desde uma simples refatoração até técnicas avançadas com objetos parciais. Vamos lá!
\n\nPor que isso é um problema? A maldição posicional
\nEm TypeScript (assim como em JavaScript), os parâmetros da função são passados em ordem. Se você tem uma função:
\nfunction createUser(\n name: string,\n age?: number,\n email?: string,\n isAdmin?: boolean\n) { /* ... */ }\nVocê não pode chamá-la assim: createUser('John', , 'john@mail.com'). Pular um parâmetro deixa um buraco que o TypeScript não aceita. Você terá que passar undefined ou null, o que polui o código e a lógica.
Mas há uma boa notícia: podemos contornar essa limitação de várias maneiras elegantes. Vamos analisar cada uma.
\n\nMétodo 1: Objeto de parâmetros (o mais correto)
\nEste é o padrão recomendado em projetos sérios. Em vez de vários parâmetros posicionais, usamos um único objeto com campos opcionais:
\ninterface UserOptions {\n name: string;\n age?: number;\n email?: string;\n isAdmin?: boolean;\n}\n\nfunction createUser(options: UserOptions): void {\n const { name, age, email, isAdmin } = options;\n console.log(`Usuário ${name} criado, idade: ${age ?? 'não informada'}`);\n}\n\n// Agora podemos passar apenas o necessário!\ncreateUser({ name: 'Ana', email: 'ana@mail.com' });\ncreateUser({ name: 'Pedro', isAdmin: true });\n\nAs vantagens são óbvias:
\n- \n
- Não importa quantos parâmetros – passamos apenas o que precisamos \n
- Código autodocumentado: fica claro o que cada coisa faz \n
- Fácil adicionar novos campos sem alterar a assinatura \n
Essa abordagem resolve 90% dos problemas com parâmetros opcionais. Mas se você está trabalhando com código legado ou não pode alterar a API – continue lendo.
\n\nMétodo 2: Sobrecarga de funções (function overloading)
\nTypeScript permite declarar várias assinaturas para uma mesma função. Isso é útil quando você tem combinações específicas de parâmetros:
\n// Declarando as sobrecargas\nfunction getData(url: string): Promise<any>;\nfunction getData(url: string, timeout: number): Promise<any>;\nfunction getData(url: string, timeout: number, retries: number): Promise<any>;\n\n// Implementação (deve ser a mais genérica)\nfunction getData(\n url: string,\n timeout?: number,\n retries?: number\n): Promise<any> {\n // lógica\n return fetch(url, { signal: AbortSignal.timeout(timeout ?? 5000) });\n}\n\n// Agora podemos chamar assim:\ngetData('/api/users'); // timeout = 5000 (padrão)\ngetData('/api/users', 3000); // timeout = 3000\n// Mas assim – não é possível (pular timeout não é permitido sem sobrecarga):\n// getData('/api/users', undefined, 2); // ruim\n\nDesvantagem: as sobrecargas não resolvem o problema de pular parâmetros intermediários. Elas apenas fornecem combinações estritas. Para uma passagem flexível, é melhor usar o primeiro método.
\n\nMétodo 3: Parâmetros Rest + desestruturação (exótico)
\nSe você quiser manter a posicionalidade, mas adicionar flexibilidade, pode usar tuplas com rest:
\ntype OptionalParams = [number, string?, boolean?];\n\nfunction processData(\n required: string,\n ...opt