typescriptbest practicesdesarrollotype-safety

TypeScript en Producción: Guía Práctica

By Binary Core

TypeScript se ha convertido en el estándar de facto para el desarrollo JavaScript en equipos grandes. Pero usar TypeScript no garantiza código robusto. Aquí compartimos nuestras lecciones aprendidas en Binary Core.

Arquitectura de Tipos

Tipos de Dominio vs Tipos de Implementación

typescript
// ❌ Mal: Tipos de implementación expuestos interface UserRepository { save(user: { id: string; name: string; email: string }): Promise<void>; } // ✅ Bien: Tipos de dominio separados interface User { id: UserId; name: string; email: Email; } class UserId extends Brand<string, 'UserId'> {} class Email extends Brand<string, 'Email'> {} interface UserRepository { save(user: User): Promise<void>; }

Tipos Discriminados

Los tipos discriminados son esenciales para modelar estados complejos:

typescript
type AsyncState<T> = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: T } | { status: 'error'; error: Error }; function handleState<T>(state: AsyncState<T>) { switch (state.status) { case 'idle': return 'Nothing happening'; case 'loading': return 'Loading...'; case 'success': return `Got ${state.data}`; case 'error': return `Error: ${state.error.message}`; } }

Patrones Avanzados

Template Literal Types

Para validación de strings en tiempo de compilación:

typescript
type EventName = `on${Capitalize<string>}`; type ValidEvents = EventName extends `on${infer E}` ? E extends 'Click' | 'Hover' | 'Focus' ? E : never : never; // ValidEvents = 'Click' | 'Hover' | 'Focus'

Inferencia de Tipos

Deja que TypeScript infiera cuando sea posible:

typescript
// ❌ Mal: Especificar tipos innecesariamente const users: User[] = await fetchUsers(); // ✅ Bien: Inferir del contexto const users = await fetchUsers<User>(); // ✅ Mejor: Tipos de retorno explícitos para funciones públicas async function fetchUsers(): Promise<User[]> { const response = await fetch('/api/users'); return response.json(); }

Configuración de TypeScript

Strict Mode

Nunca desactives el strict mode. Si algo no compila, arregla el código, no el compilador:

json
{ "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true } }

Path Aliases

Usa path aliases para imports limpios:

json
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"], "@lib/*": ["src/lib/*"] } } }

Testing con TypeScript

Tipos de Test

Los tests también deben ser type-safe:

typescript
describe('UserRepository', () => { it('should save user', async () => { const user: User = { id: new UserId('123'), name: 'John', email: new Email('john@example.com') }; await repository.save(user); const saved = await repository.findById(user.id); expect(saved).toEqual(user); }); });

Performance

Evita any

any es el enemigo de TypeScript. Usa unknown cuando no conoces el tipo:

typescript
// ❌ Mal function processData(data: any) { return data.value; } // ✅ Bien function processData(data: unknown) { if (typeof data === 'object' && data !== null && 'value' in data) { return (data as { value: unknown }).value; } throw new Error('Invalid data'); }

Type Guards

Crea type guards reutilizables:

typescript
function isUser(value: unknown): value is User { return ( typeof value === 'object' && value !== null && 'id' in value && 'name' in value && 'email' in value ); } function processValue(value: unknown) { if (isUser(value)) { // TypeScript sabe que value es User console.log(value.name); } }

Herramientas

ESLint + TypeScript

json
{ "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking" ], "rules": { "@typescript-eslint/no-explicit-any": "error", "@typescript-eslint/explicit-function-return-type": "warn", "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }] } }

Conclusión

TypeScript es una herramienta poderosa, pero requiere disciplina. En Binary Core, cada línea de código pasa por revisión de tipos antes de llegar a producción.

Binary Core

Equipo Binary Core

← Back to blog