Lección 99: Módulos, Path Aliases y Buenas Prácticas
🎯 Objetivo: Organizar proyectos TypeScript con módulos ES6, barrel files, path aliases y configuración óptima de tsconfig.json.
1. Import/Export con tipos
Section titled “1. Import/Export con tipos”Exportaciones nombradas y por defecto
Section titled “Exportaciones nombradas y por defecto”💻 Ejemplo
export interface Usuario { id: string; nombre: string; email: string;}
export type Rol = "admin" | "user" | "guest";
export function crearUsuario(nombre: string, email: string): Usuario { return { id: crypto.randomUUID(), nombre, email };}
// Export por defectoexport default class ServicioUsuarios { /* ... */ }import ServicioUsuarios, { Usuario, Rol, crearUsuario } from "./models/usuario";export type — Export explícito de tipos
Section titled “export type — Export explícito de tipos”export type ID = string;export interface Respuesta<T> { datos: T; error: string | null;}
// En tsconfig.json con isolatedModules: true, necesario para re-exportar tiposexport type { ID, Respuesta };
// Re-exportar desde otro archivoexport { Usuario } from "./usuario";export type { Usuario } from "./usuario"; // Explícito como tipo2. Barrel files (index.ts)
Section titled “2. Barrel files (index.ts)”Un barrel file (index.ts) agrupa y re-exporta múltiples módulos de un directorio.
export { Usuario, Rol, crearUsuario } from "./usuario";export { Producto, Categoria } from "./producto";export { Pedido, EstadoPedido } from "./pedido";export type { RespuestaAPI } from "./api";// src/app.ts — importación limpiaimport { Usuario, Producto, Pedido, EstadoPedido } from "./models";// En lugar de:// import { Usuario } from "./models/usuario";// import { Producto } from "./models/producto";🧠 Ventajas: Importaciones más limpias, oculta la estructura interna del directorio, facilita refactors.
3. Configuración de tsconfig.json
Section titled “3. Configuración de tsconfig.json”moduleResolution
Section titled “moduleResolution”Controla cómo TypeScript resuelve los módulos.
{ "compilerOptions": { "moduleResolution": "node" }}| Opción | Descripción |
|---|---|
node | Resolución clásica de Node.js (busca index.ts, .js, .json) |
classic | Legado, no recomendado |
bundler | Para proyectos con bundlers (Vite, esbuild) — más permisiva |
node16 / nodenext | Para ESM nativo de Node 16+ |
module
Section titled “module”{ "compilerOptions": { "module": "ESNext", "moduleResolution": "bundler" }}Para Node.js:
{ "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext" }}4. Path Aliases (paths y baseUrl)
Section titled “4. Path Aliases (paths y baseUrl)”Los aliases evitan rutas relativas profundas como ../../../utils/helpers.
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"], "@utils/*": ["src/utils/*"], "@types/*": ["src/types/*"] } }}// En lugar de:import { formatDate } from "../../../utils/date";
// Usamos:import { formatDate } from "@utils/date";import { Button } from "@components/Button";import { Usuario } from "@/models/usuario";Configuración para el bundler
Section titled “Configuración para el bundler”Si usas Vite, también necesitas configurar los aliases en vite.config.ts:
import { defineConfig } from "vite";import path from "path";
export default defineConfig({ resolve: { alias: { "@": path.resolve(__dirname, "./src"), "@components": path.resolve(__dirname, "./src/components"), }, },});5. isolatedModules
Section titled “5. isolatedModules”Cuando esta opción está activada, cada archivo se transpila de forma independiente (como hacen Vite, esbuild, Babel).
{ "compilerOptions": { "isolatedModules": true }}⚠️ Implicaciones:
- No puedes usar
const enum(necesitan información de otros archivos). - Debes usar
export typepara re-exportar tipos. - Las re-exportaciones ambiguas generan error.
// ❌ Error con isolatedModulesexport { Usuario } from "./usuario";
// ✅ Correctoexport type { Usuario } from "./usuario";export { crearUsuario } from "./usuario";6. import type vs import
Section titled “6. import type vs import”TypeScript 4.5+ permite diferenciar imports de tipo y de valor.
// Import de tipo — se borra en la compilaciónimport type { Usuario } from "./models";import type { Response } from "express";
// Import de valorimport express from "express";import { crearUsuario } from "./models";
// Mixto (una línea)import { crearUsuario, type Usuario } from "./models";🧠 Beneficios: Los imports de tipo no generan código en el JS final. Mejora el rendimiento de compilación con isolatedModules.
7. Estructura recomendada de proyecto
Section titled “7. Estructura recomendada de proyecto”mi-proyecto/├── src/│ ├── components/│ │ ├── Button.ts│ │ └── index.ts│ ├── models/│ │ ├── usuario.ts│ │ ├── producto.ts│ │ └── index.ts│ ├── services/│ │ ├── api.ts│ │ └── index.ts│ ├── utils/│ │ ├── date.ts│ │ ├── validators.ts│ │ └── index.ts│ ├── types/│ │ ├── index.ts│ │ └── global.d.ts│ └── index.ts (entry point)├── tests/├── tsconfig.json├── package.json└── vite.config.ts / webpack.config.js// tsconfig.json completo{ "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "baseUrl": ".", "paths": { "@/*": ["src/*"], "@components/*": ["src/components/*"], "@utils/*": ["src/utils/*"], "@services/*": ["src/services/*"] }, "strict": true, "esModuleInterop": true, "isolatedModules": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "./dist" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"]}8. Consejos finales
Section titled “8. Consejos finales”// 1. Prefiere import type para tiposimport type { User } from "./types";
// 2. Usa barrel files para simplificar imports// src/services/index.tsexport { apiService } from "./api";export type { ApiResponse } from "./api";
// 3. Configura paths para evitar rutas relativas largas// Con paths: import { formatDate } from "@utils/date";// Sin paths: import { formatDate } from "../../../utils/date";
// 4. isolatedModules activado = código más robusto para bundlers// 5. Usa export/import type cuando re-exportes solo tipos📝 Resumen: Los módulos ES6 con barrel files simplifican la organización del proyecto. Los path aliases (paths + baseUrl) eliminan rutas relativas confusas. isolatedModules garantiza compatibilidad con bundlers modernos. import type optimiza la compilación separando claramente tipos de valores.