Clean Code em TypeScript: princípios e exemplos na prática
\n\nTodo desenvolvedor já passou pela situação em que, um mês após escrever o código, seu próprio script parece estranho e incompreensível. No mundo do TypeScript, onde a tipagem forte oferece vantagens, os princípios do Clean Code tornam-se especialmente importantes. Código limpo não é apenas estética, mas uma ferramenta para reduzir bugs, acelerar o desenvolvimento e facilitar o trabalho em equipe. Neste artigo, vamos explorar os princípios-chave do Clean Code em TypeScript com exemplos reais que ajudarão você a escrever código fácil de ler, testar e manter.
\n\n1. Nomenclatura: diga o que a variável faz
\n\nA primeira coisa que um desenvolvedor vê são os nomes de variáveis, funções e classes. Um nome ruim faz o leitor perder tempo tentando decifrar. No TypeScript, com seu sistema de tipos, o nome deve ser autodocumentável.
\n\nExemplo ruim:
\nconst d = new Date();\nconst arr = [1, 2, 3];\nfunction proc(x: number, y: number) {\n return x * y;\n}\n\nExemplo bom:
\nconst currentDate = new Date();\nconst userScores: number[] = [1, 2, 3];\nfunction calculateArea(width: number, height: number): number {\n return width * height;\n}\n\nUse substantivos para variáveis e verbos para funções. Evite abreviações (exceto as amplamente aceitas, como id ou url). O TypeScript permite adicionar tipos, mas o nome ainda deve refletir a essência.
2. Funções: pequenas, limpas e previsíveis
\n\nUma função deve fazer apenas uma coisa. Se você não consegue pensar em um nome curto para a função, provavelmente ela está fazendo demais. Também é importante evitar efeitos colaterais.
\n\nPrincípio da responsabilidade única (SRP) no nível de funções:
\n\n// Ruim: a função faz tudo de uma vez\nfunction processUserData(user: User): void {\n // Validação\n if (!user.email) throw new Error('Email required');\n // Salvar no BD\n database.save(user);\n // Enviar email\n emailService.sendWelcome(user.email);\n}\n\n// Bom: separamos as responsabilidades\nfunction validateUser(user: User): boolean {\n return user.email !== undefined;\n}\n\nfunction saveUser(user: User): void {\n database.save(user);\n}\n\nfunction sendWelcomeEmail(email: string): void {\n emailService.send(email);\n}\n\nfunction processUser(user: User): void {\n if (!validateUser(user)) {\n throw new Error('Invalid user data');\n }\n saveUser(user);\n sendWelcomeEmail(user.email);\n}\n\nEvite também um grande número de parâmetros. Se houver mais de dois, agrupe-os em um objeto:
\n\n// Ruim\nfunction createUser(name: string, email: string, age: number, isAdmin: boolean): void {}\n\n// Bom\ninterface CreateUserParams {\n name: string;\n email: string;\n age: number;\n isAdmin: boolean;\n}\n\nfunction createUser(params: CreateUserParams): void {}\n\n3. Tipagem: use os recursos do TypeScript ao máximo
\n\nUma das principais vantagens do TypeScript é a tipagem forte. Mas muitos desenvolvedores usam any como uma muleta, matando todo o benefício. Código limpo em TypeScript é código onde os tipos são explicitamente descritos, não adivinhados.
Evite any:
// Ruim\nfunction getData(): any {\n return fetch('/api/data');\n}\n\n// Bom\ninterface ApiResponse {\n id: number;\n title: string;\n}\n\nasync function getData(): Promise<ApiResponse> {\n const response = await fetch('/api/data');\n return response.json();\n}\n\nUse discriminated unions para estados complexos:
\n// Ruim: não está claro o que há no objeto\ntype Status = 'loading' | 'success' | 'error';\n\ninterface State {\n status: Status;\n data?: Data;\n error?: string;\n}\n\n// Bom: cada