Introdução: por que a pergunta sobre @types/* atormenta até desenvolvedores experientes?
Você já passou uma hora debugando um erro que, no final, se resumia ao posicionamento incorreto do pacote @types/* no package.json? Se sim — você não está sozinho. A pergunta «How do I decide whether @types/* goes into dependencies or devDependencies?» acumulou milhares de visualizações no Stack Overflow e se tornou uma verdadeira dor de cabeça para a comunidade TypeScript.
Parece simples, não? Colocar os tipos em devDependencies e pronto. Mas não é bem assim. Quando seu projeto começa a crescer, bibliotecas de terceiros, monorepositórios e pipelines de CI/CD são adicionados, e o posicionamento incorreto dos tipos pode levar a erros fatais de build, quedas inesperadas em produção ou, pior ainda, à perda silenciosa da tipagem.
Neste artigo, vamos analisar os 5 erros mais comuns ao trabalhar com @types/*, aprender a tomar a decisão correta com base em cenários reais e criar um checklist que o protegerá de problemas. Pronto? Vamos lá!
Erro nº1: «Todos os @types/* sempre vão em devDependencies» — um mito que quebra builds
O conselho mais popular na internet é: «Tipos não são código em runtime, portanto devem estar sempre em devDependencies». E isso em 90% dos casos é realmente verdade. Mas há uma exceção importante que muitos esquecem.
Quando devDependencies é a escolha correta
Se você está escrevendo uma aplicação (servidor web em Express, frontend React, utilitário de linha de comando), então todos os @types/* podem ir tranquilamente para devDependencies. Seu usuário final não compila TypeScript — ele executa o JavaScript já compilado. Os tipos são necessários apenas para você durante o desenvolvimento.
// Exemplo para uma aplicação em Express{ "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.11.0", "typescript": "^5.3.3" }}Quando devDependencies é um erro fatal
Agora imagine: você está desenvolvendo uma biblioteca que exporta tipos TypeScript para consumidores externos. Se os tipos da sua biblioteca dependem de @types/express e você o colocou em devDependencies, o usuário que instalar sua biblioteca não receberá esses tipos automaticamente. E a IDE dele começará a mostrar sublinhados vermelhos.
// ❌ Incorreto para uma biblioteca que exporta tipos{ "devDependencies": { "@types/express": "^4.17.21" // O usuário não verá esses tipos! }}
// ✅ Correto{ "dependencies": { "@types/express": "^4.17.21" // Os tipos estarão disponíveis para os consumidores }}Regra de ouro: Se sua biblioteca reexporta tipos de um pacote @types/* ou os utiliza em uma API pública, esse pacote deve estar em dependencies. Se os tipos são usados apenas internamente — devDependencies.
Erro nº2: Ignorar a diferença entre «uso no código» e «uso nos tipos»
Muitos desenvolvedores confundem: «Eu importo Request de express, então express deve estar em dependencies». Isso é verdade para o próprio pacote express, mas não para seus tipos.
Vamos analisar com um exemplo concreto. Existem três cenários de uso do pacote @types/lodash:
- Cenário A: Você escreve
import _ from 'lodash'e usa_.chunk(). Os tipos são necessários apenas para compilação —devDependencies. - Cenário B: Você cria uma função
function mySort(arr: T[]): T[]e internamente usa_.orderBy. Os tipos não são expostos externamente —devDependencies. - Cenário C: Você escreve
export function proc