Clean Code em TypeScript: princípios e exemplos
No desenvolvimento web moderno, o TypeScript se tornou o padrão de facto para criar aplicações grandes e confiáveis. No entanto, o TypeScript por si só não garante a qualidade do código. Para que um projeto permaneça flexível, compreensível e facilmente mantível, é necessário seguir os princípios do Clean Code. Neste artigo, vamos analisar os conceitos principais de código limpo em TypeScript com exemplos práticos. Você aprenderá como escrever código que agradará não apenas o compilador, mas também seus colegas.
Por que o Clean Code é importante para o TypeScript?
O TypeScript adiciona tipagem estática ao JavaScript, o que já ajuda a evitar muitos erros. Mas os tipos são apenas uma ferramenta. Sem uma arquitetura bem pensada e um estilo legível, o código ainda se transforma em um "spaghetti". Clean Code é uma filosofia que torna o código:
- Legível — qualquer desenvolvedor entenderá rapidamente a lógica.
- Mantível — alterações em um lugar não quebram toda a aplicação.
- Escalável — adicionar novas funcionalidades não exige reescrever metade do projeto.
A aplicação desses princípios em TypeScript permite usar todo o poder do sistema de tipos, criando um código autodocumentado.
Princípio 1: Nomeação de variáveis e funções
Um bom nome é metade do sucesso. O nome deve responder às perguntas "o quê?" e "por quê?", e não "como?". Evite variáveis de uma letra e abreviações que só você entende.
Exemplo ruim:
// O que é d? E y?const d = new Date();const y = d.getFullYear();const fn = (a: number, b: number) => a + b;Exemplo bom:
const currentDate = new Date();const currentYear = currentDate.getFullYear();
const sum = (firstNumber: number, secondNumber: number): number => { return firstNumber + secondNumber;};Dica: Use nomes significativos. Para valores booleanos, use prefixos is, has, should. Por exemplo: isActive, hasPermission.
Princípio 2: Funções devem ser pequenas e fazer uma única coisa
Uma função não deve ser responsável por várias tarefas ao mesmo tempo. Se uma função faz mais de uma ação — é hora de dividi-la. Isso aumenta a reutilização e simplifica os testes.
Exemplo ruim (função faz tudo de uma vez):
function processUserData(user: any) { // Validação if (!user.email || !user.name) { throw new Error('Invalid user'); } // Formatação const formattedUser = { fullName: user.name.toUpperCase(), emailDomain: user.email.split('@')[1] }; // Salvamento no BD database.save(formattedUser); // Envio de email emailService.sendWelcomeEmail(formattedUser);}Exemplo bom (separação de responsabilidades):
function validateUser(user: User): void { if (!user.email || !user.name) { throw new Error('Invalid user data'); }}
function formatUser(user: User): FormattedUser { return { fullName: user.name.toUpperCase(), emailDomain: user.email.split('@')[1] };}
async function processUserData(user: User): Promise<void> { validateUser(user); const formattedUser = formatUser(user); await database.save(formattedUser); await emailService.sendWelcomeEmail(formattedUser);}Cada função agora tem um objetivo claro, e é fácil testá-las individualmente.
Princípio 3: Use tipos e interfaces para autodocumentação
O TypeScript oferece ferramentas poderosas para descrever dados. Não abuse do tipo any — ele anula todos os benefícios da tipagem estática. Defina interfaces