Arquitetura softwareFrontend webTypeScriptClean Code
Naming Conventions em TypeScript
Baixar PDFComo nomear variáveis, funções, tipos e constantes de forma que o código se explique — exemplos full-stack.
Naming Conventions em TypeScript
"Nomes ruins são a maior fonte de confusão em código." — Robert C. Martin
O nome de uma variável, função ou tipo deve responder a três perguntas:
- O que é? (dado, função, classe, constante)
- O que faz? (ação, verificação, transformação)
- Do que precisa? (contexto, restrições)
Regras gerais
Nomes intencionais, não genéricos
// ❌ Genérico — não diz nada
const d = new Date();
const data = await fetch('/api/users');
const temp = users.filter(u => u.active);
const flag = true;
// ✅ Intencional — diz exatamente o que é
const currentDate = new Date();
const activeUsersResponse = await fetch('/api/users');
const activeUsers = users.filter(u => u.isActive);
const isSubscriptionActive = true;Variáveis booleanas: prefixo is/has/can/should
O prefixo transforma a variável em uma pergunta que o leitor entende imediatamente.
// ❌ Sem prefixo — dúvida: é boolean ou string? É estado ou verificação?
const active = user.status === 'active';
const admin = user.role === 'admin';
const premium = user.plan !== 'free';
// ✅ Com prefixo — lê como frase
const isActive = user.status === 'active';
const isAdmin = user.role === 'admin';
const hasPremiumAccess = user.plan !== 'free';
const canEditDocument = user.role === 'admin' || document.authorId === user.id;
const shouldShowUpgradeBanner = !hasPremiumAccess && user.trialDaysRemaining < 7;Funções: verbo + substantivo
// ❌ Substantivo puro — parece propriedade, não ação
const user(id: string) { /* ... */ }
const total(items: CartItem[]) { /* ... */ }
// ❌ Verbo genérico — não diz o que processa
function process(data: any) { /* ... */ }
function handle(event: any) { /* ... */ }
function doStuff(thing: any) { /* ... */ }
// ✅ Verbo + substantivo — diz exatamente o que faz
function getUserById(id: string): Promise<User | null> { /* ... */ }
function calculateCartTotal(items: CartItem[]): number { /* ... */ }
function validateEmailFormat(email: string): boolean { /* ... */ }
function formatCurrencyToBRL(amount: number): string { /* ... */ }Prefixos comuns por contexto
| Prefixo | Significado | Exemplo |
|---|---|---|
get | Busca/obtém (pode retornar null) | getUserById, getAuthToken |
find | Busca (pode não encontrar) | findByEmail, findNearestStore |
create | Cria novo registro | createOrder, createNotification |
update | Atualiza existente | updateUserProfile, updateCartQuantity |
delete/remove | Remove | deleteUser, removeFromCart |
is/has/can/should | Retorna boolean | isActive, hasPermission, canAccess |
format | Formata para exibição | formatDateToBR, formatCurrency |
parse | Converte string para tipo | parseJwt, parseCSV |
validate | Verifica validade | validateEmail, validateCPF |
handle/on | Reage a evento | handleSubmit, onPaymentSuccess |
fetch/load | Busca de API/remoto | fetchProducts, loadUserData |
Convenções por elemento
| Elemento | Convenção | Exemplo |
|---|---|---|
| Variáveis | camelCase | userName, activeUsers |
| Funções | camelCase + verbo | getUserById, calculateTotal |
| Classes | PascalCase | UserService, HttpClient |
| Interfaces | PascalCase (sem I prefix) | User, ApiResponse |
| Types | PascalCase | Status, Currency, MouseEvent |
| Enums | PascalCase | OrderStatus, PaymentMethod |
| Constantes | UPPER_SNAKE_CASE | MAX_RETRY_COUNT, API_BASE_URL |
| Private members | prefixo _ ou # | _cache, #internalState |
| Generics | T + descrição | T, TData, TError, TResponse |
| Arquivos de componente | PascalCase | UserProfile.tsx, PaymentForm.tsx |
| Arquivos de utilidade | kebab-case | format-date.ts, validate-cpf.ts |
| Arquivos de hook | camelCase + prefixo use | useAuth.ts, useProducts.ts |
Nomes em contextos full-stack
Frontend — Componentes e hooks
// ❌ Nomes ruins
function Comp1({ d }: any) {
const [x, setX] = useState(null);
const y = useCallback(() => { /* ... */ }, []);
return <div onClick={y}>{d?.n}</div>;
}
// ✅ Nomes claros
interface UserCardProps {
user: User;
onSelect: (userId: string) => void;
}
function UserCard({ user, onSelect }: UserCardProps) {
const [isExpanded, setIsExpanded] = useState(false);
const handleSelect = useCallback(() => onSelect(user.id), [user.id, onSelect]);
return (
<div onClick={handleSelect}>
<h3>{user.name}</h3>
{isExpanded && <p>{user.email}</p>}
</div>
);
}Backend — Services e repositories
// ❌ Nomes ruins
class Svc {
async go(id: string) {
const x = await this.repo.one(id);
if (!x) throw new Error('no');
return x;
}
}
// ✅ Nomes claros
class OrderService {
async getOrderWithItems(orderId: string): Promise<OrderWithItems | null> {
const order = await this.orderRepository.findById(orderId);
if (!order) {
throw new NotFoundError(`Pedido ${orderId} não encontrado`);
}
const items = await this.orderItemRepository.findByOrderId(orderId);
return { ...order, items };
}
}Tipos e enums
// ❌ Nomes ruins
type T = { n: string; a: number };
enum S { A, B, C }
// ✅ Nomes claros
interface UserProfile {
name: string;
age: number;
}
enum OrderStatus {
Pending = 'pending',
Processing = 'processing',
Shipped = 'shipped',
Delivered = 'delivered',
Cancelled = 'cancelled',
}Anti-padrões de nomenclatura
| Anti-padrão | Exemplo | Problema |
|---|---|---|
| Siglas obscuras | usrMgt, procOrd | Não dizem nada sem contexto |
| Números no final | user1, data2 | Parecem duplicatas, não variantes |
| Nomes genéricos | data, result, temp, obj | Qualquer coisa pode ter esse nome |
| Prefixos húngaros | strName, intAge | TypeScript já tem tipos — redundante |
| Negativas em boolean | isNotActive, hasNoPermission | Difícil de ler com !: !isNotActive |
| Verbos em variáveis | getUser, calculateTotal | Parecem funções, não dados |
Regra de ouro
Se você precisa de um comentário para explicar o que uma variável/função faz, o nome está ruim.
// ❌ Precisa de comentário
// Verifica se o usuário pode acessar o recurso
function check(u: User, r: Resource) { /* ... */ }
// ✅ O nome já é a documentação
function canUserAccessResource(user: User, resource: Resource): boolean { /* ... */ }