Clean Code en TypeScript: principios y ejemplos en la práctica
\n\nCada desarrollador se ha encontrado con la situación en la que, un mes después de escribir el código, su propio script parece ajeno e incomprensible. En el mundo de TypeScript, donde la tipificación estricta ofrece una ventaja, los principios de Clean Code se vuelven especialmente importantes. El código limpio no es solo estética, sino una herramienta para reducir errores, acelerar el desarrollo y facilitar el trabajo en equipo. En este artículo, analizaremos los principios clave de Clean Code en TypeScript con ejemplos reales que le ayudarán a escribir código que sea fácil de leer, probar y mantener.
\n\n1. Nomenclatura: diga lo que hace la variable
\n\nLo primero que ve un desarrollador son los nombres de variables, funciones y clases. Un nombre deficiente obliga al lector a perder tiempo descifrando. En TypeScript, con su sistema de tipos, el nombre debe ser autodocumentado.
\n\nEjemplo incorrecto:
\nconst d = new Date();\nconst arr = [1, 2, 3];\nfunction proc(x: number, y: number) {\n return x * y;\n}\n\nEjemplo correcto:
\nconst currentDate = new Date();\nconst userScores: number[] = [1, 2, 3];\nfunction calculateArea(width: number, height: number): number {\n return width * height;\n}\n\nUse sustantivos para variables y verbos para funciones. Evite abreviaturas (excepto las comúnmente aceptadas como id o url). TypeScript permite agregar tipos, pero el nombre debe reflejar la esencia.
2. Funciones: pequeñas, limpias y predecibles
\n\nUna función debe hacer solo una cosa. Si no puede pensar en un nombre corto para una función, probablemente está haciendo demasiado. También es importante evitar efectos secundarios.
\n\nPrincipio de responsabilidad única (SRP) a nivel de funciones:
\n\n// Mal: la función lo hace todo a la vez\nfunction processUserData(user: User): void {\n // Validación\n if (!user.email) throw new Error('Email required');\n // Guardar en BD\n database.save(user);\n // Enviar email\n emailService.sendWelcome(user.email);\n}\n\n// Bien: separamos 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\nTambién evite un gran número de parámetros. Si hay más de dos, agrúpelos en un objeto:
\n\n// Mal\nfunction createUser(name: string, email: string, age: number, isAdmin: boolean): void {}\n\n// Bien\ninterface CreateUserParams {\n name: string;\n email: string;\n age: number;\n isAdmin: boolean;\n}\n\nfunction createUser(params: CreateUserParams): void {}\n\n3. Tipificación: use las capacidades de TypeScript al máximo
\n\nUna de las principales ventajas de TypeScript es la tipificación estricta. Pero muchos desarrolladores usan any como un parche, eliminando todo el beneficio. El código limpio en TypeScript es código donde los tipos están explícitamente definidos, no adivinados.
Evite any:
// Mal\nfunction getData(): any {\n return fetch('/api/data');\n}\n\n// Bien\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 uniones discriminadas para estados complejos:
\n// Mal: no está claro qué hay en el objeto\ntype Status = 'loading' | 'success' | 'error';\n\ninterface State {\n status: Status;\n data?: Data;\n error?: string;\n}\n\n// Bien: cada